Home > Mobile >  Typescript: get exact type of variable
Typescript: get exact type of variable

Time:09-17

Having an object like

const translations = {
  say_hello: 'hello {{name}}',
};

I'd like to extract the exact type of the object, like

type Translations = {
  say_hello: 'hello {{name}}',
}

So far I'm playing around something like

type GetExactType<T> = {[K in keyof T]-?: T[K]};

but it doesn't work as expected, because

  GetExactType<typeof translations>;

resolves to

{
   say_hello: string,
}

Any ideas?

CodePudding user response:

You could use as const but that results in readonly on everything, which might not be desirable.

Instead, you could have a function to narrow it for you:

type Narrow<T> =
    | (T extends infer U ? U : never)
    | Extract<T, number | string | boolean | bigint | symbol | null | undefined | []>
    | ([T] extends [[]] ? [] : { [K in keyof T]: Narrow<T[K]> });

function narrow<T>(t: Narrow<T>): T {
    return t as T;
}

And then when you use it, it'll infer the types for you:

const translations = narrow({
  say_hello: 'hello {{name}}',
});

type T = typeof translations;
//   ^? { say_hello: 'hello {{name}}'; }

Note that it is impossible to retrieve the original type after you define it like this:

const translations = {
  say_hello: 'hello {{name}}',
};

so some sort of direct operation on the value before it is assigned is required.

Playground

CodePudding user response:

You have to tell TypeScript that the say_hello property's type is 'hello {{name}}', not string. There are at least a couple of ways to do that:

  1. Via as const, saying that the object won't change:

    const translations = {
        say_hello: 'hello {{name}}',
    } as const;
    //^^^^^^^^
    type Translations = typeof translations;
    
  2. Explicitly:

    const translations = {
        say_hello: 'hello {{name}}' as 'hello {{name}}',
    // −−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^
    };
    type Translations = typeof translations;
    

    (but...ewww...)

    or

    const translations: { say_hello: 'hello {{name}}' } = {
        say_hello: 'hello {{name}}',
    };
    type Translations = typeof translations;
    // (But if you were going to do that, you'd just want to write the type
    // alias manually and then apply it to the `translations` constant, rather
    // than doing it this way around.)
    

I use the as const for things like translation strings all the time.

Playground link

  • Related