Skip to content
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

Compatibility check for nested conditional types allows unknown properties in second level of nesting #28616

Closed
timargra opened this issue Nov 20, 2018 · 1 comment · Fixed by #30853
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript

Comments

@timargra
Copy link

TypeScript Version: 3.2.0-dev.20181117

Code

export type View<T> = { [K in keyof T]: T[K] extends object ? boolean | View<T[K]> : boolean };

interface TypeC {
    foo: string;
    bar: string;
}

interface TypeB {
    foo: string,
    bar: TypeC
}

interface TypeA {
    foo: string,
    bar: TypeB,
}

let test: View<TypeA>;

test = { foo: true, bar: true, boo: true } // error TS2322: Type '{ foo: true; bar: true; boo: boolean; }' is not assignable to type 'View<TypeA>'. Object literal may only specify known properties, and 'boo' does not exist in type 'View<TypeA>'.

test = { foo: true, bar: { foo: true, bar: true, boo: true } } // error TS2322:  Type '{ foo: true; bar: { foo: true; bar: true; boo: boolean; }; }' is not assignable to type 'View<TypeA>'. Types of property 'bar' are incompatible. Type '{ foo: true; bar: true; boo: boolean; }' is not assignable to type 'boolean | View<TypeB>'. Object literal may only specify known properties, and 'boo' does not exist in type 'boolean | View<TypeB>'.

Expected behavior:

test = { foo: true, bar: { foo: true, bar: { foo: true, bar: true, boo: true } } } // error TS2322:  Type '{ foo: true; bar: { foo: true; bar: { foo: true; bar: true; boo: true }; }; }' is not assignable to type 'View<TypeA>'. Types of property 'bar' are incompatible...

Actual behavior:

test = { foo: true, bar: { foo: true, bar: { foo: true, bar: true, boo: true } } } // no error!
@jack-williams
Copy link
Collaborator

jack-williams commented Nov 20, 2018

This is covered by #20863. After the first bar property check which has type boolean | View<TypeB> excesses property checking gets disabled for nested properties because of the union type.

See this code in checker.ts

// Above we check for excess properties with respect to the entire target type. When union
// and intersection types are further deconstructed on the target side, we don't want to
// make the check again (as it might fail for a partial target type). Therefore we obtain
// the regular source type and proceed with that.
if (isUnionOrIntersectionTypeWithoutNullableConstituents(target) && !discriminantType) {
    source = getRegularTypeOfObjectLiteral(source);
}

@weswigham @RyanCavanaugh @sandersn

Would a reasonable (but partial) fix be to only drop the freshness if the union has >1 object-like types?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
In Discussion Not yet reached consensus Suggestion An idea for TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants