mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
Fix contextual typing for symbol-named properties (#46558)
* Properly handle symbol-named properties in contextual types * Update index signature in PropertyDescriptorMap * Add regression tests
This commit is contained in:
parent
373accf28f
commit
33fe1b6ffc
@ -26122,12 +26122,12 @@ namespace ts {
|
||||
return !!(getCheckFlags(symbol) & CheckFlags.Mapped && !(symbol as MappedSymbol).type && findResolutionCycleStartIndex(symbol, TypeSystemPropertyName.Type) >= 0);
|
||||
}
|
||||
|
||||
function getTypeOfPropertyOfContextualType(type: Type, name: __String) {
|
||||
function getTypeOfPropertyOfContextualType(type: Type, name: __String, nameType?: Type) {
|
||||
return mapType(type, t => {
|
||||
if (isGenericMappedType(t)) {
|
||||
const constraint = getConstraintTypeFromMappedType(t);
|
||||
const constraintOfConstraint = getBaseConstraintOfType(constraint) || constraint;
|
||||
const propertyNameType = getStringLiteralType(unescapeLeadingUnderscores(name));
|
||||
const propertyNameType = nameType || getStringLiteralType(unescapeLeadingUnderscores(name));
|
||||
if (isTypeAssignableTo(propertyNameType, constraintOfConstraint)) {
|
||||
return substituteIndexedMappedType(t, propertyNameType);
|
||||
}
|
||||
@ -26143,7 +26143,7 @@ namespace ts {
|
||||
return restType;
|
||||
}
|
||||
}
|
||||
return findApplicableIndexInfo(getIndexInfosOfStructuredType(t), getStringLiteralType(unescapeLeadingUnderscores(name)))?.type;
|
||||
return findApplicableIndexInfo(getIndexInfosOfStructuredType(t), nameType || getStringLiteralType(unescapeLeadingUnderscores(name)))?.type;
|
||||
}
|
||||
return undefined;
|
||||
}, /*noReductions*/ true);
|
||||
@ -26173,7 +26173,8 @@ namespace ts {
|
||||
// For a (non-symbol) computed property, there is no reason to look up the name
|
||||
// in the type. It will just be "__computed", which does not appear in any
|
||||
// SymbolTable.
|
||||
return getTypeOfPropertyOfContextualType(type, getSymbolOfNode(element).escapedName);
|
||||
const symbol = getSymbolOfNode(element);
|
||||
return getTypeOfPropertyOfContextualType(type, symbol.escapedName, getSymbolLinks(symbol).nameType);
|
||||
}
|
||||
if (element.name) {
|
||||
const nameType = getLiteralTypeFromPropertyName(element.name);
|
||||
|
||||
2
src/lib/es5.d.ts
vendored
2
src/lib/es5.d.ts
vendored
@ -96,7 +96,7 @@ interface PropertyDescriptor {
|
||||
}
|
||||
|
||||
interface PropertyDescriptorMap {
|
||||
[s: string]: PropertyDescriptor;
|
||||
[key: PropertyKey]: PropertyDescriptor;
|
||||
}
|
||||
|
||||
interface Object {
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
//// [contextuallyTypedSymbolNamedProperties.ts]
|
||||
// Repros from #43628
|
||||
|
||||
const A = Symbol("A");
|
||||
const B = Symbol("B");
|
||||
|
||||
type Action =
|
||||
| {type: typeof A, data: string}
|
||||
| {type: typeof B, data: number}
|
||||
|
||||
declare const ab: Action;
|
||||
|
||||
declare function f<T extends { type: string | symbol }>(action: T, blah: { [K in T['type']]: (p: K) => void }): any;
|
||||
|
||||
f(ab, {
|
||||
[A]: ap => { ap.description },
|
||||
[B]: bp => { bp.description },
|
||||
})
|
||||
|
||||
const x: { [sym: symbol]: (p: string) => void } = { [A]: s => s.length };
|
||||
|
||||
|
||||
//// [contextuallyTypedSymbolNamedProperties.js]
|
||||
"use strict";
|
||||
// Repros from #43628
|
||||
const A = Symbol("A");
|
||||
const B = Symbol("B");
|
||||
f(ab, {
|
||||
[A]: ap => { ap.description; },
|
||||
[B]: bp => { bp.description; },
|
||||
});
|
||||
const x = { [A]: s => s.length };
|
||||
|
||||
|
||||
//// [contextuallyTypedSymbolNamedProperties.d.ts]
|
||||
declare const A: unique symbol;
|
||||
declare const B: unique symbol;
|
||||
declare type Action = {
|
||||
type: typeof A;
|
||||
data: string;
|
||||
} | {
|
||||
type: typeof B;
|
||||
data: number;
|
||||
};
|
||||
declare const ab: Action;
|
||||
declare function f<T extends {
|
||||
type: string | symbol;
|
||||
}>(action: T, blah: {
|
||||
[K in T['type']]: (p: K) => void;
|
||||
}): any;
|
||||
declare const x: {
|
||||
[sym: symbol]: (p: string) => void;
|
||||
};
|
||||
@ -0,0 +1,73 @@
|
||||
=== tests/cases/compiler/contextuallyTypedSymbolNamedProperties.ts ===
|
||||
// Repros from #43628
|
||||
|
||||
const A = Symbol("A");
|
||||
>A : Symbol(A, Decl(contextuallyTypedSymbolNamedProperties.ts, 2, 5))
|
||||
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
|
||||
|
||||
const B = Symbol("B");
|
||||
>B : Symbol(B, Decl(contextuallyTypedSymbolNamedProperties.ts, 3, 5))
|
||||
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
|
||||
|
||||
type Action =
|
||||
>Action : Symbol(Action, Decl(contextuallyTypedSymbolNamedProperties.ts, 3, 22))
|
||||
|
||||
| {type: typeof A, data: string}
|
||||
>type : Symbol(type, Decl(contextuallyTypedSymbolNamedProperties.ts, 6, 7))
|
||||
>A : Symbol(A, Decl(contextuallyTypedSymbolNamedProperties.ts, 2, 5))
|
||||
>data : Symbol(data, Decl(contextuallyTypedSymbolNamedProperties.ts, 6, 22))
|
||||
|
||||
| {type: typeof B, data: number}
|
||||
>type : Symbol(type, Decl(contextuallyTypedSymbolNamedProperties.ts, 7, 7))
|
||||
>B : Symbol(B, Decl(contextuallyTypedSymbolNamedProperties.ts, 3, 5))
|
||||
>data : Symbol(data, Decl(contextuallyTypedSymbolNamedProperties.ts, 7, 22))
|
||||
|
||||
declare const ab: Action;
|
||||
>ab : Symbol(ab, Decl(contextuallyTypedSymbolNamedProperties.ts, 9, 13))
|
||||
>Action : Symbol(Action, Decl(contextuallyTypedSymbolNamedProperties.ts, 3, 22))
|
||||
|
||||
declare function f<T extends { type: string | symbol }>(action: T, blah: { [K in T['type']]: (p: K) => void }): any;
|
||||
>f : Symbol(f, Decl(contextuallyTypedSymbolNamedProperties.ts, 9, 25))
|
||||
>T : Symbol(T, Decl(contextuallyTypedSymbolNamedProperties.ts, 11, 19))
|
||||
>type : Symbol(type, Decl(contextuallyTypedSymbolNamedProperties.ts, 11, 30))
|
||||
>action : Symbol(action, Decl(contextuallyTypedSymbolNamedProperties.ts, 11, 56))
|
||||
>T : Symbol(T, Decl(contextuallyTypedSymbolNamedProperties.ts, 11, 19))
|
||||
>blah : Symbol(blah, Decl(contextuallyTypedSymbolNamedProperties.ts, 11, 66))
|
||||
>K : Symbol(K, Decl(contextuallyTypedSymbolNamedProperties.ts, 11, 76))
|
||||
>T : Symbol(T, Decl(contextuallyTypedSymbolNamedProperties.ts, 11, 19))
|
||||
>p : Symbol(p, Decl(contextuallyTypedSymbolNamedProperties.ts, 11, 94))
|
||||
>K : Symbol(K, Decl(contextuallyTypedSymbolNamedProperties.ts, 11, 76))
|
||||
|
||||
f(ab, {
|
||||
>f : Symbol(f, Decl(contextuallyTypedSymbolNamedProperties.ts, 9, 25))
|
||||
>ab : Symbol(ab, Decl(contextuallyTypedSymbolNamedProperties.ts, 9, 13))
|
||||
|
||||
[A]: ap => { ap.description },
|
||||
>[A] : Symbol([A], Decl(contextuallyTypedSymbolNamedProperties.ts, 13, 7))
|
||||
>A : Symbol(A, Decl(contextuallyTypedSymbolNamedProperties.ts, 2, 5))
|
||||
>ap : Symbol(ap, Decl(contextuallyTypedSymbolNamedProperties.ts, 14, 8))
|
||||
>ap.description : Symbol(Symbol.description, Decl(lib.es2019.symbol.d.ts, --, --))
|
||||
>ap : Symbol(ap, Decl(contextuallyTypedSymbolNamedProperties.ts, 14, 8))
|
||||
>description : Symbol(Symbol.description, Decl(lib.es2019.symbol.d.ts, --, --))
|
||||
|
||||
[B]: bp => { bp.description },
|
||||
>[B] : Symbol([B], Decl(contextuallyTypedSymbolNamedProperties.ts, 14, 34))
|
||||
>B : Symbol(B, Decl(contextuallyTypedSymbolNamedProperties.ts, 3, 5))
|
||||
>bp : Symbol(bp, Decl(contextuallyTypedSymbolNamedProperties.ts, 15, 8))
|
||||
>bp.description : Symbol(Symbol.description, Decl(lib.es2019.symbol.d.ts, --, --))
|
||||
>bp : Symbol(bp, Decl(contextuallyTypedSymbolNamedProperties.ts, 15, 8))
|
||||
>description : Symbol(Symbol.description, Decl(lib.es2019.symbol.d.ts, --, --))
|
||||
|
||||
})
|
||||
|
||||
const x: { [sym: symbol]: (p: string) => void } = { [A]: s => s.length };
|
||||
>x : Symbol(x, Decl(contextuallyTypedSymbolNamedProperties.ts, 18, 5))
|
||||
>sym : Symbol(sym, Decl(contextuallyTypedSymbolNamedProperties.ts, 18, 12))
|
||||
>p : Symbol(p, Decl(contextuallyTypedSymbolNamedProperties.ts, 18, 27))
|
||||
>[A] : Symbol([A], Decl(contextuallyTypedSymbolNamedProperties.ts, 18, 51))
|
||||
>A : Symbol(A, Decl(contextuallyTypedSymbolNamedProperties.ts, 2, 5))
|
||||
>s : Symbol(s, Decl(contextuallyTypedSymbolNamedProperties.ts, 18, 56))
|
||||
>s.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
>s : Symbol(s, Decl(contextuallyTypedSymbolNamedProperties.ts, 18, 56))
|
||||
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
@ -0,0 +1,77 @@
|
||||
=== tests/cases/compiler/contextuallyTypedSymbolNamedProperties.ts ===
|
||||
// Repros from #43628
|
||||
|
||||
const A = Symbol("A");
|
||||
>A : unique symbol
|
||||
>Symbol("A") : unique symbol
|
||||
>Symbol : SymbolConstructor
|
||||
>"A" : "A"
|
||||
|
||||
const B = Symbol("B");
|
||||
>B : unique symbol
|
||||
>Symbol("B") : unique symbol
|
||||
>Symbol : SymbolConstructor
|
||||
>"B" : "B"
|
||||
|
||||
type Action =
|
||||
>Action : Action
|
||||
|
||||
| {type: typeof A, data: string}
|
||||
>type : unique symbol
|
||||
>A : unique symbol
|
||||
>data : string
|
||||
|
||||
| {type: typeof B, data: number}
|
||||
>type : unique symbol
|
||||
>B : unique symbol
|
||||
>data : number
|
||||
|
||||
declare const ab: Action;
|
||||
>ab : Action
|
||||
|
||||
declare function f<T extends { type: string | symbol }>(action: T, blah: { [K in T['type']]: (p: K) => void }): any;
|
||||
>f : <T extends { type: string | symbol; }>(action: T, blah: { [K in T["type"]]: (p: K) => void; }) => any
|
||||
>type : string | symbol
|
||||
>action : T
|
||||
>blah : { [K in T["type"]]: (p: K) => void; }
|
||||
>p : K
|
||||
|
||||
f(ab, {
|
||||
>f(ab, { [A]: ap => { ap.description }, [B]: bp => { bp.description },}) : any
|
||||
>f : <T extends { type: string | symbol; }>(action: T, blah: { [K in T["type"]]: (p: K) => void; }) => any
|
||||
>ab : Action
|
||||
>{ [A]: ap => { ap.description }, [B]: bp => { bp.description },} : { [A]: (ap: unique symbol) => void; [B]: (bp: unique symbol) => void; }
|
||||
|
||||
[A]: ap => { ap.description },
|
||||
>[A] : (ap: unique symbol) => void
|
||||
>A : unique symbol
|
||||
>ap => { ap.description } : (ap: unique symbol) => void
|
||||
>ap : unique symbol
|
||||
>ap.description : string | undefined
|
||||
>ap : unique symbol
|
||||
>description : string | undefined
|
||||
|
||||
[B]: bp => { bp.description },
|
||||
>[B] : (bp: unique symbol) => void
|
||||
>B : unique symbol
|
||||
>bp => { bp.description } : (bp: unique symbol) => void
|
||||
>bp : unique symbol
|
||||
>bp.description : string | undefined
|
||||
>bp : unique symbol
|
||||
>description : string | undefined
|
||||
|
||||
})
|
||||
|
||||
const x: { [sym: symbol]: (p: string) => void } = { [A]: s => s.length };
|
||||
>x : { [sym: symbol]: (p: string) => void; }
|
||||
>sym : symbol
|
||||
>p : string
|
||||
>{ [A]: s => s.length } : { [A]: (s: string) => number; }
|
||||
>[A] : (s: string) => number
|
||||
>A : unique symbol
|
||||
>s => s.length : (s: string) => number
|
||||
>s : string
|
||||
>s.length : number
|
||||
>s : string
|
||||
>length : number
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
// @strict: true
|
||||
// @declaration: true
|
||||
// @target: esnext
|
||||
|
||||
// Repros from #43628
|
||||
|
||||
const A = Symbol("A");
|
||||
const B = Symbol("B");
|
||||
|
||||
type Action =
|
||||
| {type: typeof A, data: string}
|
||||
| {type: typeof B, data: number}
|
||||
|
||||
declare const ab: Action;
|
||||
|
||||
declare function f<T extends { type: string | symbol }>(action: T, blah: { [K in T['type']]: (p: K) => void }): any;
|
||||
|
||||
f(ab, {
|
||||
[A]: ap => { ap.description },
|
||||
[B]: bp => { bp.description },
|
||||
})
|
||||
|
||||
const x: { [sym: symbol]: (p: string) => void } = { [A]: s => s.length };
|
||||
Loading…
x
Reference in New Issue
Block a user