Microsoft/TypeScript

Confusing in narrowing and property access on type parameter with `never` base constraint

Open

#62,178 opened on Aug 2, 2025

View on GitHub
ย (1 comment)ย (0 reactions)ย (0 assignees)TypeScriptย (48,455 stars)ย (6,726 forks)batch import
Domain: check: Control FlowHelp WantedPossible Improvement

Description

๐Ÿ”Ž Search Terms

never in record unknown constraint base property access

๐Ÿ•— Version & Regression Information

  • This is the behavior in every version I tried

โฏ Playground Link

https://www.typescriptlang.org/play/?ts=6.0.0-dev.20250802#code/CYUwxgNghgTiAEkoGdnwFoHtgBUCeADiADw4B88A3gFDzwD6mArgC4GsBc8OA3NQL7VqoJHETRUGbAHkARgCtwLYgGUAFlCIAaeNNbsWFEAA8WIAHbA0WXIRJ62rCjTr1kGol3WaQfQdRY7eABLcwAzEBh8IlJ4EzNLa2xokihzPDIKAF5uAG0AIkZ9VnyAXT5qULMYMKgwBBxMTAgVIjBgsODIqlp4cygAWxAuZBYYUIBzPjpQZDBxghZgzHMRscnp+BgmVfgACgJYQeQucxAAN0iASngsigAFGEwB4OQSUfHzCbI-IUCibhNCD3I5DarIWLxCxWQHNVrgDpdGDZeAgmCDEDg0gFbbmMpkXIABnKQhMBEwMBY8H+CAAghMLCxGs0ACIgWpMCAsFRgNQgAZQW5SYByRRgZRpPA6SU-UnGcmUkLmaq1erwemM5kQABCKBIvRUcVM0LQGuVWrZHK5PL5AqFZqZQMtUE53N5-KgWmozl6-SGa0+U16s3mwUWy12Hw2vVCBhtHq8vwCQQdWoAwlAIBBZHUANbEA1GhIw1NO9ku63uu05Uus8uu+MCr0ovawCYnJURKJ2VRkG53VFPF5vYgyipkilUqqRVV0hnmoEFuiGqGJdXzx11q1u22Cmsbi31yu75tFk3rzVA3UjlQ+ui4ri1iAZrM5sD529JmkXhd1uYLJYVlUM81yfZ0GyrKAURcPoMQDaMZhAf8w0AyN1i+TY5l3RNegfH9N2fTNszzXs-AqERoDEMIdnFCN4CgA9F0LVcS0YrcKx3D17TYiBwOPD1mz2ShYKGHQQwAiMdCwgSth2eB+EfHi2WQ8MgNvK5FMvZpSLlBUqWo8xaJWej+ggPBkFeLUl24ECYS1eF2k6SIvWXWykhFBQlFHdIdC1NEMSxcgyEElguBwKTIK8G4YLAFZRioESQDEpDQ1U8x5KFFhNjgFgmBgdKGK0iAhN6Og-SS0r4HElDJMq6Sm0qvCUDwQz9kOdEBmQfs7zoXqOn2fJySqfIlXgdrjngAAySbqTsTAwjG0FkAAOiG5VbiyHJ8ijL58miyresWjq0ByGDDsO5bLvGzqXPOuh+E2Q7BDunK8oKgB3KBgipFhltxA4lquR75Nu-ggYEIA

๐Ÿ’ป Code

declare class ZodType<T> {
  _output: T;
}

declare class ZodObject<Shape, Output> extends ZodType<Output> {
  _shape: Shape;
}

type inferType<T extends ZodType<any>> = T["_output"];

interface ToolSpecifier {
  name: string;
  description: string;
  run: (params: never) => Promise<string>;
}

type ToolParameters<T extends ToolSpecifier> = Parameters<T["run"]>[0];

export type AgentToolDefaultSchema = ZodObject<any, any>;

export interface AgentToolBase<
  S extends AgentToolDefaultSchema = AgentToolDefaultSchema,
> {
  name: string;
  description: string;
  inputSchema: S;
}

type AgentToolCallback<
  S extends AgentToolDefaultSchema = AgentToolDefaultSchema,
> = (args: inferType<S>) => Promise<any>;

export interface AgentTool<
  S extends AgentToolDefaultSchema = AgentToolDefaultSchema,
> extends AgentToolBase<S> {
  run: AgentToolCallback<S>;
}

type AgentToolDescription<S extends AgentToolDefaultSchema> = {
  name: string;
  description: string;
  schema: S;
  run: AgentToolCallback<S>;
};

declare function agentTool<
  S extends AgentToolDefaultSchema = AgentToolDefaultSchema,
>({ name, description, schema, run }: AgentToolDescription<S>): AgentTool<S>;

export function analysisTool<
  T extends ToolSpecifier,
  S extends ZodObject<any, ToolParameters<T>>,
>(t: T, schema: S) {
  const { name, description } = t;
  return agentTool({
    name,
    description,
    schema,
    run: async (params) => {
      if ("point" in params && typeof params.point === "string") {
        params = {
          ...params,
        };
      }
      return await t.run(params);
    },
  });
}

๐Ÿ™ Actual behavior

Property 'point' does not exist on type 'inferType<S> & Record<"point", unknown>'.(2339)

๐Ÿ™‚ Expected behavior

This should be allowed or a better error should be reported

Additional information about the issue

This stems from inconsistent treatment of never:

declare const test: never;

if ("foo" in test) { // ok
}

test.foo; // error
test["foo"]; // ok
const { foo } = test; // ok

but given this whole thing happens at generic level it's not even apparent to the user they deal with a type parameter that has a never base constraint and that this might be the reason behind this confusing error

Contributor guide

Confusing in narrowing and property access on type parameter with `never` base constraint ยท Microsoft/TypeScript#62178 | Good First Issue