干净地推断数组值的类型

Cleanly infer the type of an array value

所以从技术上讲,我已经找到了这个问题的答案,但我正在寻找一种更简洁的方法。同样,我还没有看到任何 SO 问题或文档专门说明如何执行此操作。

首先,举个例子:我知道如果我有一个类型化数组,我可以用这种方式推断每个值的类型:

// just with types
type Tuple = [item1: number, item2: string];
type Item1Type = Tuple[0]; // type is number
type Item2Type = Tuple[1]; // type is string

// or with `typeof`
const myTuple: Tuple = [1, 'one'];
type InferredItem1Type = typeof myTuple[0]; // type is number
type InferredItem2Type = typeof myTuple[1]; // type is string

如果我有一个像这样的泛型,而我只能访问这种类型的一个实例:

// the generic type
type GenericObjectWithList<T> = {
  list: T[];
};

// the instance i have access to
const object: GenericObjectWithList<string> = {
  list: ['one', 'two', 'three'],
};

我想推断内部列表的类型。

// infer the type of the list
type InferredListType = typeof object['list'][0]; // type is string

如您所见,我已经发现我可以推断出这种类型,类似于我第一个示例中的方法,但我想知道,是否有更简洁的方法来推断这种类型?我希望有一种方法可以推断列表的单值类型而无需执行 [0]。如果没有另一种方法可以做到这一点,有人会介意解释为什么这种方法是我们 想要 推断数组值类型的唯一方法吗?

  • 列表项

数组由 number 索引,这意味着您可以使用 number 钻取数组以从该数组中获取值类型。

ArrayType[number] 通常是您执行此操作的方式。用零索引一个非元组数组几乎是一回事,但它向程序员暗示索引值对于不同的数字会不同,这是不正确的。

type StrArr = string[]
type ArrVal = StrArr[number] // string

或根据您的代码:

type InferredListType = typeof object['list'][number]; // type is string

Playground


这也适用于元组。

type MyTuple = [123, 'asd']
type TupleVal = MyTuple[number] // 123 | 'asd'

但是,当然,您丢失了该元组中每种类型的位置信息。如果你需要它,那就是你可以使用 [0][1] 等的地方。

Playground

TL;DR typeof object['list'][number]

注意:我在 2022-01-19 重写了这个答案。 您需要在对象 属性.

中保存数组的 部分

这更像是一个通用的“wiki”,而不是一个具体的答案,但它确实包含了您想要的内容。 Alex Wayne 的回答简单明了,而且是一个很好的答案。

简介

在索引类型时,您可以使用索引的类型(包括类型的并集)而不是文字值。 这适用于任何可索引对象,并且是几乎所有高级 TypeScript 的基础。

如您所知,您可以使用 typeof 获取变量的类型。 同样,您可以使用 keyof 来获取可索引类型的键的类型。
例如

type Obj1 = {
  key1: number;
  key2: string;
}

type KeyOfObj1 = keyof Obj1 // = 'key1' | 'key2'

type Obj2 = {
  [key: string]: number
}

type KeyOfObj2 = keyof Obj2 // = string

我将一步一步地完成一些例子,逐步变得更高级。

重要说明typeof obj['key']等同于(typeof obj)['key'](类似的表达方式也是如此)

当然,这些只是这类事物的“原子”。 您可以通过无数种方式组合所有这些。

为了学习更多的好“课程”,我推荐文档(尤其是 Creating Types from Types) and Advanced TypeScript on Execute Program

来自链接文档部分,“从类型创建类型”:

TypeScript’s type system is very powerful because it allows expressing types in terms of other types.

The simplest form of this idea is generics, we actually have a wide variety of type operators available to use. It’s also possible to express types in terms of values that we already have.

By combining various type operators, we can express complex operations and values in a succinct, maintainable way. In this section we’ll cover ways to express a new type in terms of an existing type or value.

  • Generics - Types which take parameters
  • Keyof Type Operator - Using the keyof operator to create new types
  • Typeof Type Operator - Using the typeof operator to create new types
  • Indexed Access Types - Using Type['a'] syntax to access a subset of a type
  • Conditional Types - Types which act like if statements in the type system
  • Mapped Types - Creating types by mapping each property in an existing type
  • Template Literal Types - Mapped types which change properties via template literal strings

如您所见,我在这里只是触及表面。继续!

对象

const obj = {
  key1: 123,
  key2: 'abc'
}

type Obj = typeof obj // = { key1: number, key2: string }

对象的键

const obj = {
  key1: 123,
  key2: 'abc'
}

type KeysOfObj = keyof typeof obj // = 'key1' | 'key2'

属性 对象

const obj = {
  key1: 123,
  key2: 'abc'
}

type Key1 = typeof obj['key1'] // = number

对象的所有属性

const obj = {
  key1: 123,
  key2: 'abc'
}

// Concise
type PropertiesOfObj = typeof obj[keyof typeof obj] // = number | string

// Verbose
type TypeOfObj = typeof obj // = { key1: number, key2: string }
type KeysOfObj = keyof TypeOfObj // = 'key1' | 'key2'
type PropertiesOfObj = TypeOfObj[KeysOfObj]
// = { key1: number, key2: string }['key1' | 'key2']
// = number | string

数组项/所有数组项

// Union of all items:
const arr1 = [1, 2, 3]
type ItemOfArr1 = typeof arr1[number] // = number

// Union of all items:
const arr2 = [1, 2, 'a', 'b']
type ItemOfArr2 = typeof arr2[number] // = number | string

// Specific item/index:
type Item2OfArr2 = typeof arr2[2] // = string

嵌套数组的项目

与上述相同的规则适用于数组。

const obj = {
  arr: ['one', 'two', 'three'],
};

// Concise
type ItemOfArr = typeof obj['arr'][number]; // = string

// Verbose
type Arr = typeof obj['arr'] // = string[]
type ItemOfArr = Arr[number] // = string
嵌套对象的

属性

const obj = {
  key1: {
    nested1: 123,
    nested2: 'abc'
  }
}

// Concise but dreadful
type Nested1 = typeof obj['key1'][keyof typeof obj['key1']] // = number | string

// Concisest that is easily understandable
type Key1 = typeof obj['key1'] // = { nested1: number, nested2: string }
type Nested1 = Key1[keyof Key1] // = number | string

// Verbose
type Key1 = typeof obj['key1'] // = { nested1: number, nested2: string }
type KeysOfKey1 = keyof Key1 // = 'nested1' | 'nested2'
type Nested1 = Key1[KeysOfKey1] // = number | string