网站搜索

Typescript:获取变量的精确类型


拥有像这样的物体

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

我想提取对象的确切类型,就像

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

到目前为止,我在玩一些像这样的东西

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

但是它没有按预期工作,因为

  GetExactType<typeof translations>;

解析为

{
   say_hello: string,
}

有什么想法吗?

答案#1

你可以使用 as const,但是那会导致所有内容都是 readonly,这可能不是你想要的。

相反,你可以有一个函数帮你缩小范围:

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;
}

然后当你使用它时,它会为你推断类型:

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

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

请注意,一旦你这样定义它,就不可能恢复原始类型:

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

所以在将值赋值之前,需要对其进行某种直接操作。

操场

答案#2

你必须告诉 TypeScript,say_hello 属性的类型是 'hello {{name}}',而不是 string。至少有几种方法可以做到这一点:

  1. 通过 as const,表示该对象不会改变:

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

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

    (但是……呃……)

    或者

    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.)
    

我经常把 as const 用于翻译字符串之类的东西。

操场链接