diff --git a/lib/lib.es5.d.ts b/lib/lib.es5.d.ts index dda476e4e3957..b7f311a98cc8e 100644 --- a/lib/lib.es5.d.ts +++ b/lib/lib.es5.d.ts @@ -1432,6 +1432,11 @@ type Required = { [P in keyof T]-?: T[P]; }; +/** + * Construct a true subset of T as defined by U + */ +type Subset = U; + /** * Make all properties in T readonly */ diff --git a/tests/baselines/reference/subsetTests.errors.txt b/tests/baselines/reference/subsetTests.errors.txt new file mode 100644 index 0000000000000..e9545369f145d --- /dev/null +++ b/tests/baselines/reference/subsetTests.errors.txt @@ -0,0 +1,93 @@ +tests/cases/compiler/subsetTests.ts(16,28): error TS2304: Cannot find name 'Subset'. +tests/cases/compiler/subsetTests.ts(27,40): error TS2304: Cannot find name 'Subset'. +tests/cases/compiler/subsetTests.ts(32,34): error TS2304: Cannot find name 'Subset'. +tests/cases/compiler/subsetTests.ts(39,28): error TS2304: Cannot find name 'Subset'. +tests/cases/compiler/subsetTests.ts(49,40): error TS2304: Cannot find name 'Subset'. +tests/cases/compiler/subsetTests.ts(62,34): error TS2304: Cannot find name 'Subset'. + + +==== tests/cases/compiler/subsetTests.ts (6 errors) ==== + interface User { + name: string; + age: number; + contact: { + email: string; + phone: string; + address: { + street: string; + country: string; + zipcode: number; + } + }; + password: string; + } + + type PersonalInformation = Subset; // Fine + + const test: PersonalInformation = { + name: 'Hans', + age: 21, + password: 'string' // Error: password does not exist in type + }; + + type WronglyTypedPersonalInformation = Subset; + + type ExcessPersonalInformation = Subset; + + // This also works for "deep" properties + + type ShippingInformation = Subset; // Fine (Omitting properties of nested properties is ok too) + + type WronglyTypedShippingInformation = Subset; + + type ExcessShippingInformation = Subset; + \ No newline at end of file diff --git a/tests/baselines/reference/subsetTests.js b/tests/baselines/reference/subsetTests.js new file mode 100644 index 0000000000000..8e0e0bdbefe6d --- /dev/null +++ b/tests/baselines/reference/subsetTests.js @@ -0,0 +1,80 @@ +//// [subsetTests.ts] +interface User { + name: string; + age: number; + contact: { + email: string; + phone: string; + address: { + street: string; + country: string; + zipcode: number; + } + }; + password: string; +} + +type PersonalInformation = Subset; // Fine + +const test: PersonalInformation = { + name: 'Hans', + age: 21, + password: 'string' // Error: password does not exist in type +}; + +type WronglyTypedPersonalInformation = Subset; + +type ExcessPersonalInformation = Subset; + +// This also works for "deep" properties + +type ShippingInformation = Subset; // Fine (Omitting properties of nested properties is ok too) + +type WronglyTypedShippingInformation = Subset; + +type ExcessShippingInformation = Subset; + + +//// [subsetTests.js] +var test = { + name: 'Hans', + age: 21, + password: 'string' // Error: password does not exist in type +}; diff --git a/tests/baselines/reference/subsetTests.symbols b/tests/baselines/reference/subsetTests.symbols new file mode 100644 index 0000000000000..1b050e9b4ff80 --- /dev/null +++ b/tests/baselines/reference/subsetTests.symbols @@ -0,0 +1,165 @@ +=== tests/cases/compiler/subsetTests.ts === +interface User { +>User : Symbol(User, Decl(subsetTests.ts, 0, 0)) + + name: string; +>name : Symbol(User.name, Decl(subsetTests.ts, 0, 16)) + + age: number; +>age : Symbol(User.age, Decl(subsetTests.ts, 1, 17)) + + contact: { +>contact : Symbol(User.contact, Decl(subsetTests.ts, 2, 16)) + + email: string; +>email : Symbol(email, Decl(subsetTests.ts, 3, 14)) + + phone: string; +>phone : Symbol(phone, Decl(subsetTests.ts, 4, 22)) + + address: { +>address : Symbol(address, Decl(subsetTests.ts, 5, 22)) + + street: string; +>street : Symbol(street, Decl(subsetTests.ts, 6, 18)) + + country: string; +>country : Symbol(country, Decl(subsetTests.ts, 7, 27)) + + zipcode: number; +>zipcode : Symbol(zipcode, Decl(subsetTests.ts, 8, 28)) + } + }; + password: string; +>password : Symbol(User.password, Decl(subsetTests.ts, 11, 6)) +} + +type PersonalInformation = SubsetPersonalInformation : Symbol(PersonalInformation, Decl(subsetTests.ts, 13, 1)) +>User : Symbol(User, Decl(subsetTests.ts, 0, 0)) + + name: string; +>name : Symbol(name, Decl(subsetTests.ts, 15, 41)) + + age: number; +>age : Symbol(age, Decl(subsetTests.ts, 16, 17)) + +}>; // Fine + +const test: PersonalInformation = { +>test : Symbol(test, Decl(subsetTests.ts, 20, 5)) +>PersonalInformation : Symbol(PersonalInformation, Decl(subsetTests.ts, 13, 1)) + + name: 'Hans', +>name : Symbol(name, Decl(subsetTests.ts, 20, 35)) + + age: 21, +>age : Symbol(age, Decl(subsetTests.ts, 21, 17)) + + password: 'string' // Error: password does not exist in type +>password : Symbol(password, Decl(subsetTests.ts, 22, 12)) + +}; + +type WronglyTypedPersonalInformation = SubsetWronglyTypedPersonalInformation : Symbol(WronglyTypedPersonalInformation, Decl(subsetTests.ts, 24, 2)) +>User : Symbol(User, Decl(subsetTests.ts, 0, 0)) + + name: string; +>name : Symbol(name, Decl(subsetTests.ts, 26, 53)) + + age: string; // Error: Types of property age are incompatible +>age : Symbol(age, Decl(subsetTests.ts, 27, 17)) + +}>; + +type ExcessPersonalInformation = SubsetExcessPersonalInformation : Symbol(ExcessPersonalInformation, Decl(subsetTests.ts, 29, 3)) +>User : Symbol(User, Decl(subsetTests.ts, 0, 0)) + + name: string; +>name : Symbol(name, Decl(subsetTests.ts, 31, 47)) + + favoriteColor: string; // Error: Property favoriteColor is missing in type User +>favoriteColor : Symbol(favoriteColor, Decl(subsetTests.ts, 32, 17)) + +}>; + +// This also works for "deep" properties + +type ShippingInformation = SubsetShippingInformation : Symbol(ShippingInformation, Decl(subsetTests.ts, 34, 3)) +>User : Symbol(User, Decl(subsetTests.ts, 0, 0)) + + name: string; +>name : Symbol(name, Decl(subsetTests.ts, 38, 41)) + + contact: { +>contact : Symbol(contact, Decl(subsetTests.ts, 39, 17)) + + address: { +>address : Symbol(address, Decl(subsetTests.ts, 40, 14)) + + street: string; +>street : Symbol(street, Decl(subsetTests.ts, 41, 18)) + + zipcode: number; +>zipcode : Symbol(zipcode, Decl(subsetTests.ts, 42, 27)) + } + } +}>; // Fine (Omitting properties of nested properties is ok too) + +type WronglyTypedShippingInformation = SubsetWronglyTypedShippingInformation : Symbol(WronglyTypedShippingInformation, Decl(subsetTests.ts, 46, 3)) +>User : Symbol(User, Decl(subsetTests.ts, 0, 0)) + + name: string; +>name : Symbol(name, Decl(subsetTests.ts, 48, 53)) + + contact: { +>contact : Symbol(contact, Decl(subsetTests.ts, 49, 17)) + + address: { +>address : Symbol(address, Decl(subsetTests.ts, 50, 14)) + + street: { +>street : Symbol(street, Decl(subsetTests.ts, 51, 18)) + + name: string; +>name : Symbol(name, Decl(subsetTests.ts, 52, 21)) + + nr: number; +>nr : Symbol(nr, Decl(subsetTests.ts, 53, 29)) + + }; // Error: Types of property street are incompatible + zipcode: number; +>zipcode : Symbol(zipcode, Decl(subsetTests.ts, 55, 14)) + } + } +}>; + +type ExcessShippingInformation = SubsetExcessShippingInformation : Symbol(ExcessShippingInformation, Decl(subsetTests.ts, 59, 3)) +>User : Symbol(User, Decl(subsetTests.ts, 0, 0)) + + name: string; +>name : Symbol(name, Decl(subsetTests.ts, 61, 47)) + + contact: { +>contact : Symbol(contact, Decl(subsetTests.ts, 62, 17)) + + address: { +>address : Symbol(address, Decl(subsetTests.ts, 63, 14)) + + street: string; +>street : Symbol(street, Decl(subsetTests.ts, 64, 18)) + + zipcode: number; +>zipcode : Symbol(zipcode, Decl(subsetTests.ts, 65, 27)) + + state: string; // Error: Property state is missing in type User +>state : Symbol(state, Decl(subsetTests.ts, 66, 28)) + } + } +}>; + diff --git a/tests/baselines/reference/subsetTests.types b/tests/baselines/reference/subsetTests.types new file mode 100644 index 0000000000000..5d804bce40bb1 --- /dev/null +++ b/tests/baselines/reference/subsetTests.types @@ -0,0 +1,160 @@ +=== tests/cases/compiler/subsetTests.ts === +interface User { + name: string; +>name : string + + age: number; +>age : number + + contact: { +>contact : { email: string; phone: string; address: { street: string; country: string; zipcode: number; }; } + + email: string; +>email : string + + phone: string; +>phone : string + + address: { +>address : { street: string; country: string; zipcode: number; } + + street: string; +>street : string + + country: string; +>country : string + + zipcode: number; +>zipcode : number + } + }; + password: string; +>password : string +} + +type PersonalInformation = SubsetPersonalInformation : any + + name: string; +>name : string + + age: number; +>age : number + +}>; // Fine + +const test: PersonalInformation = { +>test : any +>{ name: 'Hans', age: 21, password: 'string' // Error: password does not exist in type} : { name: string; age: number; password: string; } + + name: 'Hans', +>name : string +>'Hans' : "Hans" + + age: 21, +>age : number +>21 : 21 + + password: 'string' // Error: password does not exist in type +>password : string +>'string' : "string" + +}; + +type WronglyTypedPersonalInformation = SubsetWronglyTypedPersonalInformation : any + + name: string; +>name : string + + age: string; // Error: Types of property age are incompatible +>age : string + +}>; + +type ExcessPersonalInformation = SubsetExcessPersonalInformation : any + + name: string; +>name : string + + favoriteColor: string; // Error: Property favoriteColor is missing in type User +>favoriteColor : string + +}>; + +// This also works for "deep" properties + +type ShippingInformation = SubsetShippingInformation : any + + name: string; +>name : string + + contact: { +>contact : { address: { street: string; zipcode: number; }; } + + address: { +>address : { street: string; zipcode: number; } + + street: string; +>street : string + + zipcode: number; +>zipcode : number + } + } +}>; // Fine (Omitting properties of nested properties is ok too) + +type WronglyTypedShippingInformation = SubsetWronglyTypedShippingInformation : any + + name: string; +>name : string + + contact: { +>contact : { address: { street: { name: string; nr: number; }; zipcode: number; }; } + + address: { +>address : { street: { name: string; nr: number; }; zipcode: number; } + + street: { +>street : { name: string; nr: number; } + + name: string; +>name : string + + nr: number; +>nr : number + + }; // Error: Types of property street are incompatible + zipcode: number; +>zipcode : number + } + } +}>; + +type ExcessShippingInformation = SubsetExcessShippingInformation : any + + name: string; +>name : string + + contact: { +>contact : { address: { street: string; zipcode: number; state: string; }; } + + address: { +>address : { street: string; zipcode: number; state: string; } + + street: string; +>street : string + + zipcode: number; +>zipcode : number + + state: string; // Error: Property state is missing in type User +>state : string + } + } +}>; + diff --git a/tests/cases/compiler/subsetTests.ts b/tests/cases/compiler/subsetTests.ts new file mode 100644 index 0000000000000..432cdb1a2dbcd --- /dev/null +++ b/tests/cases/compiler/subsetTests.ts @@ -0,0 +1,71 @@ +interface User { + name: string; + age: number; + contact: { + email: string; + phone: string; + address: { + street: string; + country: string; + zipcode: number; + } + }; + password: string; +} + +type PersonalInformation = Subset; // Fine + +const test: PersonalInformation = { + name: 'Hans', + age: 21, + password: 'string' // Error: password does not exist in type +}; + +type WronglyTypedPersonalInformation = Subset; + +type ExcessPersonalInformation = Subset; + +// This also works for "deep" properties + +type ShippingInformation = Subset; // Fine (Omitting properties of nested properties is ok too) + +type WronglyTypedShippingInformation = Subset; + +type ExcessShippingInformation = Subset;