Skip to content

Declaration includes incorrect 'any' types for inferred nested property members #36353

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
aquark opened this issue Jan 22, 2020 · 0 comments
Open
Labels
Bug A bug in TypeScript
Milestone

Comments

@aquark
Copy link

aquark commented Jan 22, 2020

TypeScript Version: 3.5.3

Search Terms: declaration any inferred type

Code

I'm using some helper functions to construct type guards where the type predicate is inferred:

const isObject = (value: unknown): value is { [key: string]: unknown } =>
    typeof value === 'object' && value !== null
  
const isObjectWith = <S>(
  predicates: {
    readonly [P in keyof Required<S>]: (value: unknown) => value is S[P]
  },
) => (value: unknown): value is S =>
    isObject(value) && entries(predicates).every(([k, p]) => p(value[k]))

const isNumber = (x: unknown): x is number => typeof x === 'number'

const entries = <V extends object>(object: V): ReadonlyArray<readonly [string & keyof V, V[string & keyof V]]> =>
  Object.entries(object) as Array<[string & keyof V, V[string & keyof V]]>

export const isFoo = isObjectWith({
  a: isNumber,
})

export const isBar = isObjectWith({
  b: isFoo,
})

Expected behavior:
The .d.ts file should contain all the inferred property types:

export declare const isFoo: (value: unknown) => value is {
    a: number;
};
export declare const isBar: (value: unknown) => value is {
    b: {
        a: number;
    };
};
//# sourceMappingURL=repro.d.ts.map

Actual behavior:

The .d.ts file contains any for the nested property type:

export declare const isFoo: (value: unknown) => value is {
    a: number;
};
export declare const isBar: (value: unknown) => value is {
    b: {
        a: any;
    };
};
//# sourceMappingURL=repro.d.ts.map

Interestingly, if I force TypeScript to "evaluate" the inferred type using a mapped type, I get the correct result:

const _isFoo = isObjectWith({
  a: isNumber,
})
type GuardedType<T> = T extends (value: any) =>
  value is infer S ? { [K in keyof S]: S[K] }
  : never
export const isFoo: (value: unknown) => value is GuardedType<typeof _isFoo> = _isFoo

Related Issues: #19565

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Feb 6, 2020
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Feb 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

2 participants