【问题标题】:How to define a type based on values of an array?如何根据数组的值定义类型?
【发布时间】:2019-07-03 14:43:29
【问题描述】:

如果我有一个看起来像数组的类型:

type names = ['Mike', 'Jeff', 'Ben'];

我可以很容易地定义另一种类型,它具有 names 中的项目值:

type UserName = names[number]

对于函数:

function hello(name: UserName) {
  console.log(`Hello, ${name}!`)
}

我只能将MikeJeffBen 之一传递给函数hello。如果我给其他值,比如John,它就无法编译。

如果我没有type names,但有一个const 数组 names,该怎么办?

const names = ['Mike', 'Jeff', 'Ben'];

type UserName = ???;

function hello(name: UserName) {
  console.log(`Hello, ${name}!`)
}

hello('Mike');

是否可以定义这样的类型UserName

【问题讨论】:

标签: typescript typescript-typings


【解决方案1】:

再说一次,大多数时候都应该这样做:

  1. 声明类型
  2. 将这些类型设置为变量

完全按照这个顺序。

很少有人应该做相反的事情。

如果你真的需要它,你可以这样做:

const names = ['Mike', 'Jeff', 'Ben'] as ['Mike', 'Jeff', 'Ben'];

type UserName = typeof names;

因为你想要一个元组类型(['Mike', 'Jeff', 'Ben']),但默认情况下数组永远不会被推断为元组,而只能推断为数组(在这种情况下为string[])。但是,我认为做上述事情没有多大意义,我再次建议您做相反的惯用事情:

type UserName = ['Mike', 'Jeff', 'Ben'];
// however the above type is absolutely static 
// and I don't know if it can provide any benefit so maybe this is more correct:
type UserName = ('Mike' | 'Jeff' | 'Ben')[]

const names: UserName = ['Mike', 'Jeff', 'Ben'] // ok

【讨论】:

  • “一个人应该始终 1. 声明类型,2. 将这些类型设置为变量。很少有人应该做相反的事情”。你真的是说永远不应该使用type inference吗?类型推断是 TypeScript 工作方式中不可或缺的一部分,我很惊讶看到这样的建议。虽然明确地注释他们的类型并设置这些类型的值当然是可以接受的,但我不会想到告诉任何人总是这样做。尤其是因为这通常会导致代码重复。
  • @jcalz 你当然是对的,但并非总是如此。我可能很难传达我的想法,但我真的认为大多数时候算法/顺序是:声明一个类型,然后使用它,而不是相反。因为变量可能会改变,因此推断的类型。这可能会导致不良影响。换句话说,将变量和类型分开就是关注点的分离。我将“总是”改为“大部分时间”,这是我真正的意思(因为最后我写了“很少有人应该做相反的事情”)。
【解决方案2】:

TypeScript 3.4, which should be released in March 2019 中,可以告诉编译器将字符串文字元组的类型推断为字符串文字元组作为字符串文字元组,而不是string[],通过使用@ 987654322@。它应该是这样的:

const names = ['Mike', 'Jeff', 'Ben'] as const; // TS3.4 syntax
type Names = typeof names; // type Names = readonly ['Mike', 'Jeff', 'Ben'] 
type UserName = Names[number]; // 'Mike' | 'Jeff' | 'Ben'

在此之前(在 TypeScript 3.0 到 3.3 中),您可以通过使用辅助函数来获得此效果,该函数为编译器提供推断更窄类型的提示:

type Narrowable = string | number | boolean | undefined | null | void | {};
const tuple = <T extends Narrowable[]>(...t: T)=> t;
const names = tuple('Mike', 'Jeff', 'Ben');

type Names = typeof names; // type Names = ['Mike', 'Jeff', 'Ben'] 
type UserName = Names[number]; // 'Mike' | 'Jeff' | 'Ben'

(请注意,在这两种情况下,您都可以跳过中间的Names 类型,如果您愿意,只需定义type UserName = (typeof names)[number]

好的,希望对您有所帮助。祝你好运!

【讨论】:

    猜你喜欢
    • 2018-11-16
    • 1970-01-01
    • 2019-06-19
    • 2019-05-30
    • 2021-10-19
    • 2020-03-10
    • 2020-07-08
    • 2010-10-26
    • 1970-01-01
    相关资源
    最近更新 更多