Some information is lost when working with keyof against type arguments
See original GitHub issueBug Report
🔎 Search Terms
Hard topic to search for IMO, but I tried phrases like typescript generic interface lose type information
and I only found similar issues but not related.
🕗 Version & Regression Information
I was having trouble using version 4.5.5 (that we’re currently using), but I could also reproduce it in the latest version available in the playground (4.6.2). I checked versions back to 3.3.3 in the playground and they all reported the same issue.
⏯ Playground Link
Playground link with relevant code
💻 Code
// BEGIN FRAMEWORK STUFF
type ObjectKey<O, T> = {[K in keyof O]: O[K] extends T ? K : never}[keyof O & string];
interface MyInterface {
myStringValue: string;
myIntegerValue: number;
}
abstract class AbstractBase<O> {
constructor(private readonly object: O) {}
public getValue<T>(fieldName: ObjectKey<O, T>) {
return this.object[fieldName];
}
}
// END FRAMEWORK STUFF
// BEGIN IMPLEMENTATION STUFF
class MyType implements MyInterface {
myStringValue = "";
myIntegerValue = -1;
}
class MyInterfaceHolder1<I extends MyInterface> extends AbstractBase<MyInterface> {
constructor(object: I) {
super(object);
this.getValue<number>("myIntegerValue");
}
}
class MyInterfaceHolder2<I extends MyInterface> extends AbstractBase<I> {
constructor(object: I) {
super(object);
this.getValue<number>("myIntegerValue"); // Argument of type 'string' is not assignable to parameter of type 'ObjectKey<I, number>'.(2345)
}
}
// END IMPLEMENTATION STUFF
const holder1 = new MyInterfaceHolder1<MyType>(new MyType());
const value1 = holder1.getValue<number>("myIntegerValue");
const holder2 = new MyInterfaceHolder1<MyType>(new MyType());
const value2 = holder2.getValue<number>("myIntegerValue");
🙁 Actual behavior
I lose some type information within the super-class when working with a generic argument.
🙂 Expected behavior
I feel like it should be able to maintain type information here.
Issue Analytics
- State:
- Created a year ago
- Reactions:1
- Comments:5 (4 by maintainers)
Top Results From Across the Web
Why does type Record sometimes complain about missing ...
Let's start from the implementation: type Record<K extends keyof any, T> = { [P in K]: T; };. keyof any - just means...
Read more >How to use the keyof operator in TypeScript
The keyof operator takes an object type and produces a string or numeric literal union of its keys. A simple usage is shown...
Read more >Documentation - Advanced Types
This page lists some of the more advanced ways in which you can model types, it works in tandem with the Utility Types...
Read more >Master the TypeScript Keyof Type Operator | by Bytefer
This information tells us that the parameters obj and key implicitly have “any” type. To solve this problem, we can explicitly define the ......
Read more >Advanced TypeScript Types Cheat Sheet (with Examples)
TypeScript is a typed language that allows you to specify the type of variables, function parameters, returned values, and object properties ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Got around to logging #48992
There’s no way for TS to establish the higher-order relationship between what goes into
type ObjectKey<O, T> = {[K in keyof O]: O[K] extends T ? K : never}[keyof O & string];
and how that relates to the provided keys. We’d need some built-in operator to be able to deduce that this is safe; being “safe by construction” is not something the checker can recognize.