mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-07 23:08:20 -06:00
* Only include unique symbols when getting index types for access checks * Filter all nonstrings * Inline ternary
This commit is contained in:
parent
16687e6ebf
commit
a94e318604
@ -8061,12 +8061,16 @@ namespace ts {
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getIndexTypeForGenericType(type: InstantiableType | UnionOrIntersectionType) {
|
||||
if (!type.resolvedIndexType) {
|
||||
type.resolvedIndexType = <IndexType>createType(TypeFlags.Index);
|
||||
type.resolvedIndexType.type = type;
|
||||
function getIndexTypeForGenericType(type: InstantiableType | UnionOrIntersectionType, includeDeclaredTypes?: boolean) {
|
||||
const cacheLocation = includeDeclaredTypes ? "resolvedDeclaredIndexType" : "resolvedIndexType";
|
||||
if (!type[cacheLocation]) {
|
||||
type[cacheLocation] = <IndexType>createType(TypeFlags.Index);
|
||||
type[cacheLocation].type = type;
|
||||
if (includeDeclaredTypes) {
|
||||
type[cacheLocation].isDeclaredType = true;
|
||||
}
|
||||
}
|
||||
return type.resolvedIndexType;
|
||||
return type[cacheLocation];
|
||||
}
|
||||
|
||||
function getLiteralTypeFromPropertyName(prop: Symbol) {
|
||||
@ -8084,17 +8088,22 @@ namespace ts {
|
||||
return links.nameType;
|
||||
}
|
||||
|
||||
function getLiteralTypeFromPropertyNames(type: Type) {
|
||||
return getUnionType(map(getPropertiesOfType(type), getLiteralTypeFromPropertyName));
|
||||
function isTypeString(type: Type) {
|
||||
return isTypeAssignableToKind(type, TypeFlags.StringLike);
|
||||
}
|
||||
|
||||
function getIndexType(type: Type): Type {
|
||||
return type.flags & TypeFlags.Intersection ? getUnionType(map((<IntersectionType>type).types, t => getIndexType(t))) :
|
||||
maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type) :
|
||||
function getLiteralTypeFromPropertyNames(type: Type, includeDeclaredTypes?: boolean) {
|
||||
const originalKeys = map(getPropertiesOfType(type), getLiteralTypeFromPropertyName);
|
||||
return getUnionType(includeDeclaredTypes ? originalKeys : filter(originalKeys, isTypeString));
|
||||
}
|
||||
|
||||
function getIndexType(type: Type, includeDeclaredTypes?: boolean): Type {
|
||||
return type.flags & TypeFlags.Intersection ? getUnionType(map((<IntersectionType>type).types, t => getIndexType(t, includeDeclaredTypes))) :
|
||||
maybeTypeOfKind(type, TypeFlags.InstantiableNonPrimitive) ? getIndexTypeForGenericType(<InstantiableType | UnionOrIntersectionType>type, includeDeclaredTypes) :
|
||||
getObjectFlags(type) & ObjectFlags.Mapped ? getConstraintTypeFromMappedType(<MappedType>type) :
|
||||
type === wildcardType ? wildcardType :
|
||||
type.flags & TypeFlags.Any || getIndexInfoOfType(type, IndexKind.String) ? stringType :
|
||||
getLiteralTypeFromPropertyNames(type);
|
||||
getLiteralTypeFromPropertyNames(type, includeDeclaredTypes);
|
||||
}
|
||||
|
||||
function getIndexTypeOrString(type: Type): Type {
|
||||
@ -10191,7 +10200,7 @@ namespace ts {
|
||||
// constraint of T.
|
||||
const constraint = getConstraintForRelation((<IndexType>target).type);
|
||||
if (constraint) {
|
||||
if (result = isRelatedTo(source, getIndexType(constraint), reportErrors)) {
|
||||
if (result = isRelatedTo(source, getIndexType(constraint, (target as IndexType).isDeclaredType), reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -20632,7 +20641,7 @@ namespace ts {
|
||||
// Check if the index type is assignable to 'keyof T' for the object type.
|
||||
const objectType = (<IndexedAccessType>type).objectType;
|
||||
const indexType = (<IndexedAccessType>type).indexType;
|
||||
if (isTypeAssignableTo(indexType, getIndexType(objectType))) {
|
||||
if (isTypeAssignableTo(indexType, getIndexType(objectType, /*includeDeclaredTypes*/ true))) {
|
||||
if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) &&
|
||||
getObjectFlags(objectType) & ObjectFlags.Mapped && getMappedTypeModifiers(<MappedType>objectType) & MappedTypeModifiers.IncludeReadonly) {
|
||||
error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType));
|
||||
|
||||
@ -3706,6 +3706,8 @@ namespace ts {
|
||||
/* @internal */
|
||||
resolvedIndexType: IndexType;
|
||||
/* @internal */
|
||||
resolvedDeclaredIndexType: IndexType;
|
||||
/* @internal */
|
||||
resolvedBaseConstraint: Type;
|
||||
/* @internal */
|
||||
couldContainTypeVariables: boolean;
|
||||
@ -3792,6 +3794,8 @@ namespace ts {
|
||||
resolvedBaseConstraint?: Type;
|
||||
/* @internal */
|
||||
resolvedIndexType?: IndexType;
|
||||
/* @internal */
|
||||
resolvedDeclaredIndexType?: IndexType;
|
||||
}
|
||||
|
||||
// Type parameters (TypeFlags.TypeParameter)
|
||||
@ -3823,6 +3827,8 @@ namespace ts {
|
||||
|
||||
// keyof T types (TypeFlags.Index)
|
||||
export interface IndexType extends InstantiableType {
|
||||
/* @internal */
|
||||
isDeclaredType?: boolean;
|
||||
type: InstantiableType | UnionOrIntersectionType;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
tests/cases/compiler/keyofDoesntContainSymbols.ts(11,30): error TS2345: Argument of type '""' is not assignable to parameter of type 'number'.
|
||||
tests/cases/compiler/keyofDoesntContainSymbols.ts(14,23): error TS2345: Argument of type 'unique symbol' is not assignable to parameter of type '"str" | "num"'.
|
||||
tests/cases/compiler/keyofDoesntContainSymbols.ts(17,23): error TS2345: Argument of type '0' is not assignable to parameter of type '"str" | "num"'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/keyofDoesntContainSymbols.ts (3 errors) ====
|
||||
const sym = Symbol();
|
||||
const num = 0;
|
||||
const obj = { num: 0, str: 's', [num]: num as 0, [sym]: sym };
|
||||
|
||||
function set <T extends object, K extends keyof T> (obj: T, key: K, value: T[K]): T[K] {
|
||||
return obj[key] = value;
|
||||
}
|
||||
|
||||
const val = set(obj, 'str', '');
|
||||
// string
|
||||
const valB = set(obj, 'num', '');
|
||||
~~
|
||||
!!! error TS2345: Argument of type '""' is not assignable to parameter of type 'number'.
|
||||
// Expect type error
|
||||
// Argument of type '""' is not assignable to parameter of type 'number'.
|
||||
const valC = set(obj, sym, sym);
|
||||
~~~
|
||||
!!! error TS2345: Argument of type 'unique symbol' is not assignable to parameter of type '"str" | "num"'.
|
||||
// Expect type error
|
||||
// Argument of type 'unique symbol' is not assignable to parameter of type "str" | "num"
|
||||
const valD = set(obj, num, num);
|
||||
~~~
|
||||
!!! error TS2345: Argument of type '0' is not assignable to parameter of type '"str" | "num"'.
|
||||
// Expect type error
|
||||
// Argument of type '0' is not assignable to parameter of type "str" | "num"
|
||||
type KeyofObj = keyof typeof obj;
|
||||
// "str" | "num"
|
||||
type Values<T> = T[keyof T];
|
||||
|
||||
type ValuesOfObj = Values<typeof obj>;
|
||||
43
tests/baselines/reference/keyofDoesntContainSymbols.js
Normal file
43
tests/baselines/reference/keyofDoesntContainSymbols.js
Normal file
@ -0,0 +1,43 @@
|
||||
//// [keyofDoesntContainSymbols.ts]
|
||||
const sym = Symbol();
|
||||
const num = 0;
|
||||
const obj = { num: 0, str: 's', [num]: num as 0, [sym]: sym };
|
||||
|
||||
function set <T extends object, K extends keyof T> (obj: T, key: K, value: T[K]): T[K] {
|
||||
return obj[key] = value;
|
||||
}
|
||||
|
||||
const val = set(obj, 'str', '');
|
||||
// string
|
||||
const valB = set(obj, 'num', '');
|
||||
// Expect type error
|
||||
// Argument of type '""' is not assignable to parameter of type 'number'.
|
||||
const valC = set(obj, sym, sym);
|
||||
// Expect type error
|
||||
// Argument of type 'unique symbol' is not assignable to parameter of type "str" | "num"
|
||||
const valD = set(obj, num, num);
|
||||
// Expect type error
|
||||
// Argument of type '0' is not assignable to parameter of type "str" | "num"
|
||||
type KeyofObj = keyof typeof obj;
|
||||
// "str" | "num"
|
||||
type Values<T> = T[keyof T];
|
||||
|
||||
type ValuesOfObj = Values<typeof obj>;
|
||||
|
||||
//// [keyofDoesntContainSymbols.js]
|
||||
var sym = Symbol();
|
||||
var num = 0;
|
||||
var obj = (_a = { num: 0, str: 's' }, _a[num] = num, _a[sym] = sym, _a);
|
||||
function set(obj, key, value) {
|
||||
return obj[key] = value;
|
||||
}
|
||||
var val = set(obj, 'str', '');
|
||||
// string
|
||||
var valB = set(obj, 'num', '');
|
||||
// Expect type error
|
||||
// Argument of type '""' is not assignable to parameter of type 'number'.
|
||||
var valC = set(obj, sym, sym);
|
||||
// Expect type error
|
||||
// Argument of type 'unique symbol' is not assignable to parameter of type "str" | "num"
|
||||
var valD = set(obj, num, num);
|
||||
var _a;
|
||||
87
tests/baselines/reference/keyofDoesntContainSymbols.symbols
Normal file
87
tests/baselines/reference/keyofDoesntContainSymbols.symbols
Normal file
@ -0,0 +1,87 @@
|
||||
=== tests/cases/compiler/keyofDoesntContainSymbols.ts ===
|
||||
const sym = Symbol();
|
||||
>sym : Symbol(sym, Decl(keyofDoesntContainSymbols.ts, 0, 5))
|
||||
>Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --))
|
||||
|
||||
const num = 0;
|
||||
>num : Symbol(num, Decl(keyofDoesntContainSymbols.ts, 1, 5))
|
||||
|
||||
const obj = { num: 0, str: 's', [num]: num as 0, [sym]: sym };
|
||||
>obj : Symbol(obj, Decl(keyofDoesntContainSymbols.ts, 2, 5))
|
||||
>num : Symbol(num, Decl(keyofDoesntContainSymbols.ts, 2, 13))
|
||||
>str : Symbol(str, Decl(keyofDoesntContainSymbols.ts, 2, 21))
|
||||
>[num] : Symbol([num], Decl(keyofDoesntContainSymbols.ts, 2, 31))
|
||||
>num : Symbol(num, Decl(keyofDoesntContainSymbols.ts, 1, 5))
|
||||
>num : Symbol(num, Decl(keyofDoesntContainSymbols.ts, 1, 5))
|
||||
>[sym] : Symbol([sym], Decl(keyofDoesntContainSymbols.ts, 2, 48))
|
||||
>sym : Symbol(sym, Decl(keyofDoesntContainSymbols.ts, 0, 5))
|
||||
>sym : Symbol(sym, Decl(keyofDoesntContainSymbols.ts, 0, 5))
|
||||
|
||||
function set <T extends object, K extends keyof T> (obj: T, key: K, value: T[K]): T[K] {
|
||||
>set : Symbol(set, Decl(keyofDoesntContainSymbols.ts, 2, 62))
|
||||
>T : Symbol(T, Decl(keyofDoesntContainSymbols.ts, 4, 14))
|
||||
>K : Symbol(K, Decl(keyofDoesntContainSymbols.ts, 4, 31))
|
||||
>T : Symbol(T, Decl(keyofDoesntContainSymbols.ts, 4, 14))
|
||||
>obj : Symbol(obj, Decl(keyofDoesntContainSymbols.ts, 4, 52))
|
||||
>T : Symbol(T, Decl(keyofDoesntContainSymbols.ts, 4, 14))
|
||||
>key : Symbol(key, Decl(keyofDoesntContainSymbols.ts, 4, 59))
|
||||
>K : Symbol(K, Decl(keyofDoesntContainSymbols.ts, 4, 31))
|
||||
>value : Symbol(value, Decl(keyofDoesntContainSymbols.ts, 4, 67))
|
||||
>T : Symbol(T, Decl(keyofDoesntContainSymbols.ts, 4, 14))
|
||||
>K : Symbol(K, Decl(keyofDoesntContainSymbols.ts, 4, 31))
|
||||
>T : Symbol(T, Decl(keyofDoesntContainSymbols.ts, 4, 14))
|
||||
>K : Symbol(K, Decl(keyofDoesntContainSymbols.ts, 4, 31))
|
||||
|
||||
return obj[key] = value;
|
||||
>obj : Symbol(obj, Decl(keyofDoesntContainSymbols.ts, 4, 52))
|
||||
>key : Symbol(key, Decl(keyofDoesntContainSymbols.ts, 4, 59))
|
||||
>value : Symbol(value, Decl(keyofDoesntContainSymbols.ts, 4, 67))
|
||||
}
|
||||
|
||||
const val = set(obj, 'str', '');
|
||||
>val : Symbol(val, Decl(keyofDoesntContainSymbols.ts, 8, 5))
|
||||
>set : Symbol(set, Decl(keyofDoesntContainSymbols.ts, 2, 62))
|
||||
>obj : Symbol(obj, Decl(keyofDoesntContainSymbols.ts, 2, 5))
|
||||
|
||||
// string
|
||||
const valB = set(obj, 'num', '');
|
||||
>valB : Symbol(valB, Decl(keyofDoesntContainSymbols.ts, 10, 5))
|
||||
>set : Symbol(set, Decl(keyofDoesntContainSymbols.ts, 2, 62))
|
||||
>obj : Symbol(obj, Decl(keyofDoesntContainSymbols.ts, 2, 5))
|
||||
|
||||
// Expect type error
|
||||
// Argument of type '""' is not assignable to parameter of type 'number'.
|
||||
const valC = set(obj, sym, sym);
|
||||
>valC : Symbol(valC, Decl(keyofDoesntContainSymbols.ts, 13, 5))
|
||||
>set : Symbol(set, Decl(keyofDoesntContainSymbols.ts, 2, 62))
|
||||
>obj : Symbol(obj, Decl(keyofDoesntContainSymbols.ts, 2, 5))
|
||||
>sym : Symbol(sym, Decl(keyofDoesntContainSymbols.ts, 0, 5))
|
||||
>sym : Symbol(sym, Decl(keyofDoesntContainSymbols.ts, 0, 5))
|
||||
|
||||
// Expect type error
|
||||
// Argument of type 'unique symbol' is not assignable to parameter of type "str" | "num"
|
||||
const valD = set(obj, num, num);
|
||||
>valD : Symbol(valD, Decl(keyofDoesntContainSymbols.ts, 16, 5))
|
||||
>set : Symbol(set, Decl(keyofDoesntContainSymbols.ts, 2, 62))
|
||||
>obj : Symbol(obj, Decl(keyofDoesntContainSymbols.ts, 2, 5))
|
||||
>num : Symbol(num, Decl(keyofDoesntContainSymbols.ts, 1, 5))
|
||||
>num : Symbol(num, Decl(keyofDoesntContainSymbols.ts, 1, 5))
|
||||
|
||||
// Expect type error
|
||||
// Argument of type '0' is not assignable to parameter of type "str" | "num"
|
||||
type KeyofObj = keyof typeof obj;
|
||||
>KeyofObj : Symbol(KeyofObj, Decl(keyofDoesntContainSymbols.ts, 16, 32))
|
||||
>obj : Symbol(obj, Decl(keyofDoesntContainSymbols.ts, 2, 5))
|
||||
|
||||
// "str" | "num"
|
||||
type Values<T> = T[keyof T];
|
||||
>Values : Symbol(Values, Decl(keyofDoesntContainSymbols.ts, 19, 33))
|
||||
>T : Symbol(T, Decl(keyofDoesntContainSymbols.ts, 21, 12))
|
||||
>T : Symbol(T, Decl(keyofDoesntContainSymbols.ts, 21, 12))
|
||||
>T : Symbol(T, Decl(keyofDoesntContainSymbols.ts, 21, 12))
|
||||
|
||||
type ValuesOfObj = Values<typeof obj>;
|
||||
>ValuesOfObj : Symbol(ValuesOfObj, Decl(keyofDoesntContainSymbols.ts, 21, 28))
|
||||
>Values : Symbol(Values, Decl(keyofDoesntContainSymbols.ts, 19, 33))
|
||||
>obj : Symbol(obj, Decl(keyofDoesntContainSymbols.ts, 2, 5))
|
||||
|
||||
103
tests/baselines/reference/keyofDoesntContainSymbols.types
Normal file
103
tests/baselines/reference/keyofDoesntContainSymbols.types
Normal file
@ -0,0 +1,103 @@
|
||||
=== tests/cases/compiler/keyofDoesntContainSymbols.ts ===
|
||||
const sym = Symbol();
|
||||
>sym : unique symbol
|
||||
>Symbol() : unique symbol
|
||||
>Symbol : SymbolConstructor
|
||||
|
||||
const num = 0;
|
||||
>num : 0
|
||||
>0 : 0
|
||||
|
||||
const obj = { num: 0, str: 's', [num]: num as 0, [sym]: sym };
|
||||
>obj : { num: number; str: string; [num]: 0; [sym]: symbol; }
|
||||
>{ num: 0, str: 's', [num]: num as 0, [sym]: sym } : { num: number; str: string; [num]: 0; [sym]: symbol; }
|
||||
>num : number
|
||||
>0 : 0
|
||||
>str : string
|
||||
>'s' : "s"
|
||||
>[num] : 0
|
||||
>num : 0
|
||||
>num as 0 : 0
|
||||
>num : 0
|
||||
>[sym] : symbol
|
||||
>sym : unique symbol
|
||||
>sym : unique symbol
|
||||
|
||||
function set <T extends object, K extends keyof T> (obj: T, key: K, value: T[K]): T[K] {
|
||||
>set : <T extends object, K extends keyof T>(obj: T, key: K, value: T[K]) => T[K]
|
||||
>T : T
|
||||
>K : K
|
||||
>T : T
|
||||
>obj : T
|
||||
>T : T
|
||||
>key : K
|
||||
>K : K
|
||||
>value : T[K]
|
||||
>T : T
|
||||
>K : K
|
||||
>T : T
|
||||
>K : K
|
||||
|
||||
return obj[key] = value;
|
||||
>obj[key] = value : T[K]
|
||||
>obj[key] : T[K]
|
||||
>obj : T
|
||||
>key : K
|
||||
>value : T[K]
|
||||
}
|
||||
|
||||
const val = set(obj, 'str', '');
|
||||
>val : string
|
||||
>set(obj, 'str', '') : string
|
||||
>set : <T extends object, K extends keyof T>(obj: T, key: K, value: T[K]) => T[K]
|
||||
>obj : { num: number; str: string; [num]: 0; [sym]: symbol; }
|
||||
>'str' : "str"
|
||||
>'' : ""
|
||||
|
||||
// string
|
||||
const valB = set(obj, 'num', '');
|
||||
>valB : any
|
||||
>set(obj, 'num', '') : any
|
||||
>set : <T extends object, K extends keyof T>(obj: T, key: K, value: T[K]) => T[K]
|
||||
>obj : { num: number; str: string; [num]: 0; [sym]: symbol; }
|
||||
>'num' : "num"
|
||||
>'' : ""
|
||||
|
||||
// Expect type error
|
||||
// Argument of type '""' is not assignable to parameter of type 'number'.
|
||||
const valC = set(obj, sym, sym);
|
||||
>valC : any
|
||||
>set(obj, sym, sym) : any
|
||||
>set : <T extends object, K extends keyof T>(obj: T, key: K, value: T[K]) => T[K]
|
||||
>obj : { num: number; str: string; [num]: 0; [sym]: symbol; }
|
||||
>sym : unique symbol
|
||||
>sym : unique symbol
|
||||
|
||||
// Expect type error
|
||||
// Argument of type 'unique symbol' is not assignable to parameter of type "str" | "num"
|
||||
const valD = set(obj, num, num);
|
||||
>valD : any
|
||||
>set(obj, num, num) : any
|
||||
>set : <T extends object, K extends keyof T>(obj: T, key: K, value: T[K]) => T[K]
|
||||
>obj : { num: number; str: string; [num]: 0; [sym]: symbol; }
|
||||
>num : 0
|
||||
>num : 0
|
||||
|
||||
// Expect type error
|
||||
// Argument of type '0' is not assignable to parameter of type "str" | "num"
|
||||
type KeyofObj = keyof typeof obj;
|
||||
>KeyofObj : "str" | "num"
|
||||
>obj : { num: number; str: string; [num]: 0; [sym]: symbol; }
|
||||
|
||||
// "str" | "num"
|
||||
type Values<T> = T[keyof T];
|
||||
>Values : T[keyof T]
|
||||
>T : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
type ValuesOfObj = Values<typeof obj>;
|
||||
>ValuesOfObj : string | number
|
||||
>Values : T[keyof T]
|
||||
>obj : { num: number; str: string; [num]: 0; [sym]: symbol; }
|
||||
|
||||
25
tests/cases/compiler/keyofDoesntContainSymbols.ts
Normal file
25
tests/cases/compiler/keyofDoesntContainSymbols.ts
Normal file
@ -0,0 +1,25 @@
|
||||
// @lib: es6
|
||||
const sym = Symbol();
|
||||
const num = 0;
|
||||
const obj = { num: 0, str: 's', [num]: num as 0, [sym]: sym };
|
||||
|
||||
function set <T extends object, K extends keyof T> (obj: T, key: K, value: T[K]): T[K] {
|
||||
return obj[key] = value;
|
||||
}
|
||||
|
||||
const val = set(obj, 'str', '');
|
||||
// string
|
||||
const valB = set(obj, 'num', '');
|
||||
// Expect type error
|
||||
// Argument of type '""' is not assignable to parameter of type 'number'.
|
||||
const valC = set(obj, sym, sym);
|
||||
// Expect type error
|
||||
// Argument of type 'unique symbol' is not assignable to parameter of type "str" | "num"
|
||||
const valD = set(obj, num, num);
|
||||
// Expect type error
|
||||
// Argument of type '0' is not assignable to parameter of type "str" | "num"
|
||||
type KeyofObj = keyof typeof obj;
|
||||
// "str" | "num"
|
||||
type Values<T> = T[keyof T];
|
||||
|
||||
type ValuesOfObj = Values<typeof obj>;
|
||||
Loading…
x
Reference in New Issue
Block a user