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
Section A causes no TS error in the source code below.
Section B causes a TS error in the source code below.
Both sections do the same thing and section B shouldn't yield any errors. (?)
The message "Type 'boolean' is not assignable to type 'string'" also makes no sense because prop is clearly a boolean now. (?)
(?) means: I am pretty sure, but not entirely sure, as I am new to Typescript. ^^
typeTemplate={prop: number;}typeKeys<Type>=keyofType|(string&Record<never,never>);typeSomeType<T>={[PropertyinKeys<T>]?: PropertyextendskeyofT ? boolean : string;};// section A: no TS errorletsomething: SomeType<Template>={};something.prop=true;something.anotherProp='value';// section B: TS error// Type '{ prop: true; anotherProp: string; }' is not assignable to type 'SomeType<Template>'.// Property 'prop' is incompatible with index signature.// Type 'boolean' is not assignable to type 'string'something={prop: true,anotherProp: 'value',};
typeTemplate={prop: number;}typeSomeType<T>={[PropertyinkeyofT]?: boolean;}&{[s: string]: string};// section A: no TS errorletsomething: SomeType<Template>={};something.prop=true;something.anotherProp='value';// section B: TS error// Type '{ prop: true; anotherProp: string; }' is not assignable to type 'SomeType<Template>'.// Property 'prop' is incompatible with index signature.// Type 'boolean' is not assignable to type 'string'something={prop: true,anotherProp: 'value',};
It seems like you're trying to emulate rest index signatures, which aren't really supported. See #7765.
The problem with “rest” properties is, given you have { [x: string]: string, foo: number }, what should the type system do when given an arbitrary string key that happens (at runtime) to be "foo"? That’s not something the type system can verify at compile time, so TS doesn’t even try to model this case and instead treats the index signature as universal.
Note that you have to be very careful when using this pattern at runtime for the same reason - if your keys are dynamic (provided by the user, e.g.), you have to make sure they don’t overlap with the named ones.
Well, { foo: number } & { [x: string]: string } (roughly what you have in the OP) is basically the same type as { [x: string]: string, foo: number } and neither one is safe for the above reasons, is what I was getting at. Your pseudocode above would indeed be a solution, but there's currently no way to express "any string except 'foo'" - that would require Negated Types, which, judging by the fact that PR was recently closed, looks like have been taken off the table. 😢
I am not saying { [x: string]: string, foo: number } should work because this would obviously be bad design.
Yep, I agree - but you'd be surprised how many people still want that exact type to work, and will argue vehemently with you when you try to tell them it's unsafe. It's refreshing to see someone who recognizes that. 😄
Activity
RyanCavanaugh commentedon Jun 10, 2022
Simpler version:
It seems like you're trying to emulate rest index signatures, which aren't really supported. See #7765.
tippfelher commentedon Jun 11, 2022
That's very, very sad because this sounds like a very useful feature when working with types. (at least in my use cases ^.-)
So basically, in order to achieve this, I have to generate a separate file with type definitions from runtime information as relay does.
Thank you very much though.
fatcerberus commentedon Jun 11, 2022
The problem with “rest” properties is, given you have
{ [x: string]: string, foo: number }, what should the type system do when given an arbitrarystringkey that happens (at runtime) to be"foo"? That’s not something the type system can verify at compile time, so TS doesn’t even try to model this case and instead treats the index signature as universal.Note that you have to be very careful when using this pattern at runtime for the same reason - if your keys are dynamic (provided by the user, e.g.), you have to make sure they don’t overlap with the named ones.
tippfelher commentedon Jun 11, 2022
I am not saying
{ [x: string]: string, foo: number }should work because this would obviously be bad design. But if you write it asthen there would be no problem to determine the type for property
babyorfoo. (This prolly cannot be implemented in the current TS architecture)Edit: I wanted to make use of the (non-existing, because I didn't know it better) rest feature with recursion but recursion doesn't seem to work even if rest properties were supported.
fatcerberus commentedon Jun 11, 2022
Well,
{ foo: number } & { [x: string]: string }(roughly what you have in the OP) is basically the same type as{ [x: string]: string, foo: number }and neither one is safe for the above reasons, is what I was getting at. Your pseudocode above would indeed be a solution, but there's currently no way to express "any string except 'foo'" - that would require Negated Types, which, judging by the fact that PR was recently closed, looks like have been taken off the table. 😢fatcerberus commentedon Jun 11, 2022
Yep, I agree - but you'd be surprised how many people still want that exact type to work, and will argue vehemently with you when you try to tell them it's unsafe. It's refreshing to see someone who recognizes that. 😄