You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Expected behavior:
I expected StringProps1 and StringProps2 to mean the same thing (infer from just the string keys).
Accordingly, T1 and T2 would both inferred as 'aaa', both excluding the symbol key.
Actual behavior:
T2 excludes the symbol key as expected, but T1 includes it, as shown in the code comments.
Even if StringProps1 and StringProps2 did have subtly different meanings, it doesn't seem logical to include the [SYM]: 'sym' as part of the string indexer, since it doesn't belong there.
Related Issues:
This is a simpler repro of #26183, although that issue shows its nothing specific to conditional types. It seems to be just how string indexers work with type inference.
The search terms above brought up #25065 and #24560, but they don't look like the same issue.
This is working as intended. A string index signature places a constraint on every property of a type, regardless of what kind of name it has. I agree the name "string index signature" is a bit unfortunate as it affects properties that might have numeric or symbol names, but the name predates our support for those kinds of names. It would definitely be a breaking change to modify our behavior here.
Another thing I can't figure out is, if {[x: string]: T} is intended to apply to all keys (i.e., strings, symbols and numbers), then why is the following not an error?
constSYM=Symbol();declarefunctionfoo(obj: {[x: string]: number}): void;foo({a: 1,[SYM]: 'sym'});// OK
In this case, the symbol key appears not to be part of the 'string index signature' since it is not constrained to number.
From my perspective, this behaviour seems correct (ie symbols are excluded from the string index signature), and the prior 'working as intended' behaviour seems incorrect. But either way, shouldn't the inferring and the constraining behaviour both be consistent w.r.t. including symbols in the string index signature?
For context, the following code is a cut-down repro of what I'm trying to do, but I can't figure out what's going on with the compiler. Playground link.
The intent here is that all three cases should work without errors. According to Anders Hejlsberg (@ahejlsberg)'s comment above I suspect all three should be errors. In reality 2/3 work. In the end, is there a way to express the intended inference logic of the foo function?
// function foo takes an 'options' object that can have:// (a) any number of string keys whose values are unary functions// (b) an optional 'directive' unique symbol key with a unrelated typeconstdirective=Symbol('directive');declarefunctionfoo<TArg,TRet,TDir>(options:
{[xinstring]: (arg: TArg)=>TRet}// all the string keys are unary functions&{[directive]?: TDir}// there is an optional 'directive' symbol key): void;// CASE 1// ~~~ERROR~~~ - ... prop 'addOne' incompatible with index signature// ... 'x' and 'arg' are incompatible// ... 'string' not assignable to 'number'letcase1=foo({[directive]: (x: string)=>'str',addOne: (x: number)=>x+1,double: (x: number)=>x+x,});// CASE 2: identical to case 1 except for order of properties// Compiles OK - infers TArg = number, TRet = number, TDir = (x: string) => stringletcase2=foo({addOne: (x: number)=>x+1,double: (x: number)=>x+x,[directive]: (x: string)=>'str',});// CASE 3: identical to case 1 except for type of directive// Compiles OK - infers TArg = number, TRet = number, TDir = stringletcase3=foo({[directive]: 'str',addOne: (x: number)=>x+1,double: (x: number)=>x+x,});
Activity
ahejlsberg commentedon Aug 9, 2018
This is working as intended. A string index signature places a constraint on every property of a type, regardless of what kind of name it has. I agree the name "string index signature" is a bit unfortunate as it affects properties that might have numeric or symbol names, but the name predates our support for those kinds of names. It would definitely be a breaking change to modify our behavior here.
yortus commentedon Aug 10, 2018
Oh right. I just assumed the strings and symbols were separated out as part of #23592 (and the breaking change taken there).
So what about this third variation, is it also working as intended?
The
Kin that mapped type is also picking up the symbol key, soK in stringis including non-string values.yortus commentedon Aug 10, 2018
Another thing I can't figure out is, if
{[x: string]: T}is intended to apply to all keys (i.e., strings, symbols and numbers), then why is the following not an error?In this case, the symbol key appears not to be part of the 'string index signature' since it is not constrained to
number.From my perspective, this behaviour seems correct (ie symbols are excluded from the string index signature), and the prior 'working as intended' behaviour seems incorrect. But either way, shouldn't the inferring and the constraining behaviour both be consistent w.r.t. including symbols in the string index signature?
yortus commentedon Aug 10, 2018
For context, the following code is a cut-down repro of what I'm trying to do, but I can't figure out what's going on with the compiler. Playground link.
The intent here is that all three cases should work without errors. According to Anders Hejlsberg (@ahejlsberg)'s comment above I suspect all three should be errors. In reality 2/3 work. In the end, is there a way to express the intended inference logic of the
foofunction?yortus commentedon Aug 15, 2018
Closing since it's working as intended. I opened a separate issue (#26470) for the code in the preceding comment.