6

how to use a type as a parameter in Typescript

type myType = {}
const passingType = (t: Type) => {
    const x : t = {}
}

passingType(myType);

I get TS errors

't' refers to a value, but is being used as a type here. Did you mean 'typeof t'?

and

'myType' only refers to a type, but is being used as a value here.ts(2693)

for the call

any idea on how to accomplish this.

7
  • Look up "typescript type parameter". Commented Sep 29, 2020 at 14:41
  • Also known as generics Commented Sep 29, 2020 at 14:42
  • I want to pass the type as a parameter to use it in an internal check, If I pass it as a type parameter I can't make checks based on it. Commented Sep 29, 2020 at 15:06
  • What "internal check"? Can you post a minimal reproducible example that shows what you're trying to do? Commented Sep 29, 2020 at 15:23
  • First I want to know if passing a type is doable or no, Commented Sep 29, 2020 at 15:37

2 Answers 2

9

This is not possible.


TypeScript's static type system (which includes your myType definition and type annotations) is erased when the code is emitted as JavaScript. JavaScript is what actually runs at runtime. At runtime, all you can access are values. Type erasure means your code above becomes something like this:

const passingType = (t) => {
    const x = {};
};
passingType(myType);

There's no value named myType to pass to passingType.

And because TypeScript types don't exist as values at runtime, there is no "type of types" like what you're calling Type. So this approach, as stated, is not directly possible.


Instead of thinking about passing a "type" to a function at runtime, which is not fruitful, it's probably best to think specifically about what you want to happen at runtime in pure JavaScript, and then write types to support that.

What would you really want to do with a "type" at runtime? Do you want to use it to check if a value is of that type? Then instead of passing in a type you might want to pass in a type guard function:

type Guard<T> = (x: any) => x is T;
const passingType = <T,>(t: Guard<T>) => {
    if (t(undefined)) {
        console.log("undefined IS of the guarded type T");
    }  else {
        console.log("undefined is NOT of the guarded type T");
    }
}

And you could use it like this:

function isUndefined(x: any): x is undefined {
    return typeof x === "undefined";
}

passingType(isUndefined); // undefined IS of the guarded type T

function isNumber(x: any): x is number {
    return typeof x === "number";
}
passingType(isNumber); // undefined IS NOT of the guarded type T

function isNumberOrUndefined(x: any): x is number | undefined {
    return isNumber(x) || isUndefined(x);
}

passingType(isNumberOrUndefined); // undefined IS of the guarded type T

Your actual use case will drive the requirements for what the argument to passingType should look like. It might be a whole data structure representing various things you'd want to do with a "type" at runtime. So even if this type guard example doesn't work for you, it's possible that something else will.


But again, the short answer is that TypeScript's static type system is erased and thus it is impossible to refer to its types directly at runtime.

Playground link to code

Sign up to request clarification or add additional context in comments.

Comments

3

Use generics instead. Type arguments have a different syntax from emitted JS arguments. For example:

type TheType = |
  { foo: string } |
  { bar: string };
const passingType = <T extends TheType>(obj: T) => {
    return { ...obj };
};

const result = passingType({ foo: 'foo' });

This results in result, a new object created inside the function, being typed properly as { foo: string }.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.