Merge pull request #12589 from Microsoft/mappedTypeModifierInference

Mapped type modifier inference
This commit is contained in:
Anders Hejlsberg 2016-11-30 11:11:44 -08:00 committed by GitHub
commit 030da0b69f
6 changed files with 187 additions and 10 deletions

View file

@ -4532,7 +4532,7 @@ namespace ts {
const isomorphicProp = isomorphicType && getPropertyOfType(isomorphicType, propName);
const isOptional = templateOptional || !!(isomorphicProp && isomorphicProp.flags & SymbolFlags.Optional);
const prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName);
prop.type = addOptionality(propType, isOptional);
prop.type = propType;
prop.isReadonly = templateReadonly || isomorphicProp && isReadonlySymbol(isomorphicProp);
members[propName] = prop;
}
@ -4556,7 +4556,7 @@ namespace ts {
function getTemplateTypeFromMappedType(type: MappedType) {
return type.templateType ||
(type.templateType = type.declaration.type ?
instantiateType(getTypeFromTypeNode(type.declaration.type), type.mapper || identityMapper) :
instantiateType(addOptionality(getTypeFromTypeNode(type.declaration.type), !!type.declaration.questionToken), type.mapper || identityMapper) :
unknownType);
}
@ -6021,7 +6021,7 @@ namespace ts {
}
const mapper = createUnaryTypeMapper(getTypeParameterFromMappedType(type), indexType);
const templateMapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper;
return addOptionality(instantiateType(getTemplateTypeFromMappedType(type), templateMapper), !!type.declaration.questionToken);
return instantiateType(getTemplateTypeFromMappedType(type), templateMapper);
}
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode) {
@ -8484,16 +8484,18 @@ namespace ts {
const typeInferences = createTypeInferencesObject();
const typeInferencesArray = [typeInferences];
const templateType = getTemplateTypeFromMappedType(target);
const readonlyMask = target.declaration.readonlyToken ? false : true;
const optionalMask = target.declaration.questionToken ? 0 : SymbolFlags.Optional;
const properties = getPropertiesOfType(source);
const members = createSymbolTable(properties);
let hasInferredTypes = false;
for (const prop of properties) {
const inferredPropType = inferTargetType(getTypeOfSymbol(prop));
if (inferredPropType) {
const inferredProp = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | prop.flags & SymbolFlags.Optional, prop.name);
const inferredProp = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | prop.flags & optionalMask, prop.name);
inferredProp.declarations = prop.declarations;
inferredProp.type = inferredPropType;
inferredProp.isReadonly = isReadonlySymbol(prop);
inferredProp.isReadonly = readonlyMask && isReadonlySymbol(prop);
members[prop.name] = inferredProp;
hasInferredTypes = true;
}
@ -8502,7 +8504,7 @@ namespace ts {
if (indexInfo) {
const inferredIndexType = inferTargetType(indexInfo.type);
if (inferredIndexType) {
indexInfo = createIndexInfo(inferredIndexType, indexInfo.isReadonly);
indexInfo = createIndexInfo(inferredIndexType, readonlyMask && indexInfo.isReadonly);
hasInferredTypes = true;
}
}

View file

@ -103,6 +103,21 @@ function f6(s: string) {
});
let v = unboxify(b);
let x: string | number | boolean = v[s];
}
declare function validate<T>(obj: { [P in keyof T]?: T[P] }): T;
declare function clone<T>(obj: { readonly [P in keyof T]: T[P] }): T;
declare function validateAndClone<T>(obj: { readonly [P in keyof T]?: T[P] }): T;
type Foo = {
a?: number;
readonly b: string;
}
function f10(foo: Foo) {
let x = validate(foo); // { a: number, readonly b: string }
let y = clone(foo); // { a?: number, b: string }
let z = validateAndClone(foo); // { a: number, b: string }
}
//// [isomorphicMappedTypeInference.js]
@ -190,6 +205,11 @@ function f6(s) {
var v = unboxify(b);
var x = v[s];
}
function f10(foo) {
var x = validate(foo); // { a: number, readonly b: string }
var y = clone(foo); // { a?: number, b: string }
var z = validateAndClone(foo); // { a: number, b: string }
}
//// [isomorphicMappedTypeInference.d.ts]
@ -220,3 +240,17 @@ declare function makeDictionary<T>(obj: {
[x: string]: T;
};
declare function f6(s: string): void;
declare function validate<T>(obj: {
[P in keyof T]?: T[P];
}): T;
declare function clone<T>(obj: {
readonly [P in keyof T]: T[P];
}): T;
declare function validateAndClone<T>(obj: {
readonly [P in keyof T]?: T[P];
}): T;
declare type Foo = {
a?: number;
readonly b: string;
};
declare function f10(foo: Foo): void;

View file

@ -332,3 +332,64 @@ function f6(s: string) {
>v : Symbol(v, Decl(isomorphicMappedTypeInference.ts, 102, 7))
>s : Symbol(s, Decl(isomorphicMappedTypeInference.ts, 96, 12))
}
declare function validate<T>(obj: { [P in keyof T]?: T[P] }): T;
>validate : Symbol(validate, Decl(isomorphicMappedTypeInference.ts, 104, 1))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 106, 26))
>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 106, 29))
>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 106, 37))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 106, 26))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 106, 26))
>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 106, 37))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 106, 26))
declare function clone<T>(obj: { readonly [P in keyof T]: T[P] }): T;
>clone : Symbol(clone, Decl(isomorphicMappedTypeInference.ts, 106, 64))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 107, 23))
>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 107, 26))
>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 107, 43))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 107, 23))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 107, 23))
>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 107, 43))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 107, 23))
declare function validateAndClone<T>(obj: { readonly [P in keyof T]?: T[P] }): T;
>validateAndClone : Symbol(validateAndClone, Decl(isomorphicMappedTypeInference.ts, 107, 69))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 108, 34))
>obj : Symbol(obj, Decl(isomorphicMappedTypeInference.ts, 108, 37))
>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 108, 54))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 108, 34))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 108, 34))
>P : Symbol(P, Decl(isomorphicMappedTypeInference.ts, 108, 54))
>T : Symbol(T, Decl(isomorphicMappedTypeInference.ts, 108, 34))
type Foo = {
>Foo : Symbol(Foo, Decl(isomorphicMappedTypeInference.ts, 108, 81))
a?: number;
>a : Symbol(a, Decl(isomorphicMappedTypeInference.ts, 110, 12))
readonly b: string;
>b : Symbol(b, Decl(isomorphicMappedTypeInference.ts, 111, 15))
}
function f10(foo: Foo) {
>f10 : Symbol(f10, Decl(isomorphicMappedTypeInference.ts, 113, 1))
>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 115, 13))
>Foo : Symbol(Foo, Decl(isomorphicMappedTypeInference.ts, 108, 81))
let x = validate(foo); // { a: number, readonly b: string }
>x : Symbol(x, Decl(isomorphicMappedTypeInference.ts, 116, 7))
>validate : Symbol(validate, Decl(isomorphicMappedTypeInference.ts, 104, 1))
>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 115, 13))
let y = clone(foo); // { a?: number, b: string }
>y : Symbol(y, Decl(isomorphicMappedTypeInference.ts, 117, 7))
>clone : Symbol(clone, Decl(isomorphicMappedTypeInference.ts, 106, 64))
>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 115, 13))
let z = validateAndClone(foo); // { a: number, b: string }
>z : Symbol(z, Decl(isomorphicMappedTypeInference.ts, 118, 7))
>validateAndClone : Symbol(validateAndClone, Decl(isomorphicMappedTypeInference.ts, 107, 69))
>foo : Symbol(foo, Decl(isomorphicMappedTypeInference.ts, 115, 13))
}

View file

@ -403,3 +403,67 @@ function f6(s: string) {
>v : { [x: string]: string | number | boolean; }
>s : string
}
declare function validate<T>(obj: { [P in keyof T]?: T[P] }): T;
>validate : <T>(obj: { [P in keyof T]?: T[P] | undefined; }) => T
>T : T
>obj : { [P in keyof T]?: T[P] | undefined; }
>P : P
>T : T
>T : T
>P : P
>T : T
declare function clone<T>(obj: { readonly [P in keyof T]: T[P] }): T;
>clone : <T>(obj: { readonly [P in keyof T]: T[P]; }) => T
>T : T
>obj : { readonly [P in keyof T]: T[P]; }
>P : P
>T : T
>T : T
>P : P
>T : T
declare function validateAndClone<T>(obj: { readonly [P in keyof T]?: T[P] }): T;
>validateAndClone : <T>(obj: { readonly [P in keyof T]?: T[P] | undefined; }) => T
>T : T
>obj : { readonly [P in keyof T]?: T[P] | undefined; }
>P : P
>T : T
>T : T
>P : P
>T : T
type Foo = {
>Foo : Foo
a?: number;
>a : number | undefined
readonly b: string;
>b : string
}
function f10(foo: Foo) {
>f10 : (foo: Foo) => void
>foo : Foo
>Foo : Foo
let x = validate(foo); // { a: number, readonly b: string }
>x : { a: number; readonly b: string; }
>validate(foo) : { a: number; readonly b: string; }
>validate : <T>(obj: { [P in keyof T]?: T[P] | undefined; }) => T
>foo : Foo
let y = clone(foo); // { a?: number, b: string }
>y : { a?: number | undefined; b: string; }
>clone(foo) : { a?: number | undefined; b: string; }
>clone : <T>(obj: { readonly [P in keyof T]: T[P]; }) => T
>foo : Foo
let z = validateAndClone(foo); // { a: number, b: string }
>z : { a: number; b: string; }
>validateAndClone(foo) : { a: number; b: string; }
>validateAndClone : <T>(obj: { readonly [P in keyof T]?: T[P] | undefined; }) => T
>foo : Foo
}

View file

@ -16,9 +16,9 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(38,24): error TS2344: T
Type 'T' is not assignable to type '"visible"'.
Type 'string | number' is not assignable to type '"visible"'.
Type 'string' is not assignable to type '"visible"'.
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(60,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]?: T[P]; }'.
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(60,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]?: T[P] | undefined; }'.
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(61,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]: T[P]; }'.
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(62,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]?: T[P]; }'.
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(62,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]?: T[P] | undefined; }'.
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(67,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]: T[P][]; }'.
@ -112,13 +112,13 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(67,9): error TS2403: Su
var x: { [P in keyof T]: T[P] };
var x: { [P in keyof T]?: T[P] }; // Error
~
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]?: T[P]; }'.
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ [P in keyof T]?: T[P] | undefined; }'.
var x: { readonly [P in keyof T]: T[P] }; // Error
~
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]: T[P]; }'.
var x: { readonly [P in keyof T]?: T[P] }; // Error
~
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]?: T[P]; }'.
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '{ [P in keyof T]: T[P]; }', but here has type '{ readonly [P in keyof T]?: T[P] | undefined; }'.
}
function f12<T>() {

View file

@ -1,3 +1,4 @@
// @strictNullChecks: true
// @noimplicitany: true
// @declaration: true
@ -104,4 +105,19 @@ function f6(s: string) {
});
let v = unboxify(b);
let x: string | number | boolean = v[s];
}
declare function validate<T>(obj: { [P in keyof T]?: T[P] }): T;
declare function clone<T>(obj: { readonly [P in keyof T]: T[P] }): T;
declare function validateAndClone<T>(obj: { readonly [P in keyof T]?: T[P] }): T;
type Foo = {
a?: number;
readonly b: string;
}
function f10(foo: Foo) {
let x = validate(foo); // { a: number, readonly b: string }
let y = clone(foo); // { a?: number, b: string }
let z = validateAndClone(foo); // { a: number, b: string }
}