Access values associated with a generic type in TypeScript

2 days ago 1
ARTICLE AD BOX
trait Foo<F> { const FOO: F; } struct Bar; impl Foo<u8> for Bar { const FOO: u8 = 1; } fn foo<T, F>() -> F where T: Foo<F>, { T::FOO } fn main() { println!("{}", foo::<Bar, _>()); // Prints: 1 }

In the above Rust code, fn foo can access the value FOO from the generic type T, and I want to achieve something similar with TypeScript.

I have tried the code below, but is does not work:

interface Foo<F> { foo: F; } class Bar { foo: 1 = 1; } function foo<T extends Foo<F>, F>(): F { return T.foo; // 'T' only refers to a type, but is being used as a value here.(2693) } console.log(foo<Bar, 1>());

And I have to pass a value foo_ to make the above code work:

interface Foo<F> { foo: F; } class Bar { foo: 1 = 1; } function foo<T extends Foo<F>, F>(foo_: T): F { return foo_.foo; } console.log(foo<Bar, 1>({foo: 1}));

I have two questions about this in particular:

Is there any way in which I can make T.foo accessible to function foo without passing in an actual T value, like I do in the Rust code? That is, how can I pass a type parameter to a function, which the function can actually read? As a sidenote, I have read this answer, which is quite similar to my case, but that does not allow the function foo to be generic over a type T.

I am aware that, when the code is transpiled into JavaScript, all type information gets erased, which is why return T.foo is not transpilable to JavaScript, and hence the error. However, the transpiler should be able to infer that, 1) given any type T extends Foo<F>, there must be a field on the type T named foo with the type F; and 2) for any value of type Bar, it must have a field foo, which makes Bar fulfill the interface Foo, and the field foo is always 1. With that knowledge, the transpiler should be able to emit something like foo(Bar.foo) or even foo(1) when it sees foo<Bar, 1>(). Can I make the TypeScript transpiler do such inference? If yes, how? If no, why?

Read Entire Article