Question Details

No question body available.

Tags

typescript generics

Answers (2)

Accepted Answer Available
Accepted Answer
April 19, 2026 Score: 1 Rep: 340,776 Quality: High Completeness: 80%

As asked what you are trying to do is intentionally impossible in TypeScript.

As you are apparently aware, TypeScript's type system is erased upon compilation to JavaScript. Indeed, for most (but unfortunately not all) features of TypeScript, the compilation step to a sufficiently new version of JavaScript is only type erasure: simply remove all the type-level code (the annotations and interfaces) and your TypeScript is now JavaScript! This makes the runtime behavior of TypeScript code tractable and straightforward to reason about. It completely separates the concerns of type checking from code emitting.

This is all intentional and one of the foundational goals of TypeScript. Inversely, adding any kind of type-system information to the emitted code is an explicitly-stated non-goal of TypeScript (specifically Non Goal #5). So what you are trying to do is explicitly and intentionally not supported.


The "right" way to think about TypeScript code is to imagine writing pure JavaScript code, and then using the type system to help you make sure that your code is going to do the right thing at runtime. You use TypeScript's type system to describe what JavaScript does, not to modify what it does. Type inference makes it easier to write that code, but it doesn't provide values. If you need a value at runtime, you have to provide that value. TypeScript's type system can't and won't do that for you.

The conventional approach to your example therefore looks more like:

interface Foo {
  foo: F;
}

class Bar { foo: 1 = 1; }

function foo(foo: T): T["foo"] { return foo.foo; }

const result = foo(new Bar()) // ^? const result: 1

console.log(result);

Here your foo() function is generic in only one type parameter, T. The type parameter you named F can be computed from T using the indexed access type T["foo"]. When you call foo() you could simply pass in a new value {foo: 1}, but then it has nothing to do with your Bar class. If you want there to be some relationship to your actual Bar class, then you should pass in an actual Bar instance. So foo(new Bar()) (or, instead of new Bar(), some instance of Bar you have around somewhere). That gives you the expected and desired result, where foo(new Bar()) produces a value of type 1 at runtime.

Again, TypeScript is just describing JavaScript for you. If you want that value of type 1 at runtime you need to put it somewhere. If foo() is supposed to represent what happens when you index into a value of type T with a key of "foo", then you need to give it such a value and index into it with a key of "foo". TypeScript is able to see what it will do and infer types for you so you don't have to explicitly write foo(new Bar()). But TypeScript cannot, will not, should not -- change what it will do.

A value of type 1 is presumably easy to get and create on demand. If the value were more complicated and expensive, then I'd imagine you'd have that as a constant somewhere to begin with and then just keep referring to it:

const val = { a: 1, b: 2, c: 3 }; // something more complicated
class Baz {
  foo = val;
}
const r2 = foo(new Baz());
//    ^? const r2: { a: number; b: number; c: number; }

But then at that point foo and Baz seem like a longwinded way to write

const r2 = val;

which means you'd have to be more thoughtful about what you actually want TypeScript to help you do here. Is it important that some Foo somewhere in the universe has a property of some specific type F even if you never want to actually use the value of type Foo? Maybe you don't need foo and your classes at all. Or maybe you do need them but the information you thought was just TypeScript type information really needs to be some kind of Javascript schema object:

interface FooMaker {
  schema: { F: F };
  new(): Foo
}
class Bar {
  static readonly schema = { F: 1 } as const
  foo = Bar.schema.F
}
function schemaF(ctor: FooMaker): F {
  return ctor.schema.F
}
const result = schemaF(Bar);
//    ^? const result: 1

The specifics aren't super important here, but the idea is you need to put all the information you care about into JavaScript and then you can use TypeScript to keep track of it, so you don't need to do things like instantiate a class when you don't actually want an instance of a class.

At this point I'm just speculating about the underlying use case so I'll stop. If another question post appears with more information I'll look at that one.

Playground link to code

April 18, 2026 Score: 2 Rep: 41 Quality: Low Completeness: 20%

The issue is that TypeScript type parameters are erased entirely at runtime, so T in foo() produces no JavaScript and you cannot read values from it.

To answer your second question first: no, the TypeScript compiler will not emit foo(Bar.foo) or foo(1) when it sees foo(). Type arguments are hints to the type checker only. The emitted JavaScript for foo() is just foo(), full stop. TypeScript has no monomorphization pass and is not designed to