Merge pull request #12589 from Microsoft/mappedTypeModifierInference
Mapped type modifier inference
This commit is contained in:
commit
030da0b69f
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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>() {
|
||||
|
|
|
@ -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 }
|
||||
}
|
Loading…
Reference in a new issue