为什么 TypeScript 递归类型别名因泛型而失败
Why does TypeScript recursive type alias fail with generics
我有两个描述几乎相同事物的类型定义:
// compilation fails with `Type alias 'StringOrRecordOfStrings' circularly references itself.ts(2456)`
type StringOrRecordOfStrings = string | string[] | Record<string, StringOrRecordOfStrings>;
// compiles without problems
type StringOrRecordOfStrings = string | string[] | { [property: string]: StringOrRecordOfStrings };
有谁能解释为什么第一个类型定义不能编译?
- 递归类型别名已在 3.7 版中引入https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#more-recursive-type-aliases
- 这个 SO 答案解释了如何使用递归类型别名 Recursive Types in TypeScript
- 为简洁起见,我从记录中省略了剩余的键类型,但即使我们设置
[property: string | number | symbol]
. 它也能正常工作
不允许 Record<string, StringOrRecordOfStrings>
的原因是 Record
是通用 类型 ,而不是 class 或接口。
这方面没有很多明确的文档,但是对象中的属性、索引签名和映射类型的递归类型引用已经存在了很长一段时间。以下内容早在 TypeScript 3.3 就可以使用:
type Recursive = {p: Recursive} | {[p: string]: Recursive} | {[Key in 'a']: Recursive}
这就是检查第二个示例类型(带有索引签名)的原因。
TypeScript 3.7 扩展了对递归引用的支持,如 PR:
中所述
- 泛型实例化 class 和接口类型(例如
Array<Foo>
)。
- 数组类型(例如
Foo[]
)。
- 元组类型(例如
[string, Foo?]
)。
所以现在,这三个例子也是有效的:
type RecursiveCI = Promise<RecursiveCI>
type RecursiveT = [number, boolean, RecursiveT]
type RecursiveA = RecursiveA[]
我假设该示例只是测试代码,但您可以使用像这样的辅助界面对其进行类型检查:
type StringOrRecordOfStrings = string | string[] | Record<string, RecordInterface>
interface RecordInterface extends Record<string, StringOrRecordOfStrings> {}
我有两个描述几乎相同事物的类型定义:
// compilation fails with `Type alias 'StringOrRecordOfStrings' circularly references itself.ts(2456)`
type StringOrRecordOfStrings = string | string[] | Record<string, StringOrRecordOfStrings>;
// compiles without problems
type StringOrRecordOfStrings = string | string[] | { [property: string]: StringOrRecordOfStrings };
有谁能解释为什么第一个类型定义不能编译?
- 递归类型别名已在 3.7 版中引入https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#more-recursive-type-aliases
- 这个 SO 答案解释了如何使用递归类型别名 Recursive Types in TypeScript
- 为简洁起见,我从记录中省略了剩余的键类型,但即使我们设置
[property: string | number | symbol]
. 它也能正常工作
不允许 Record<string, StringOrRecordOfStrings>
的原因是 Record
是通用 类型 ,而不是 class 或接口。
这方面没有很多明确的文档,但是对象中的属性、索引签名和映射类型的递归类型引用已经存在了很长一段时间。以下内容早在 TypeScript 3.3 就可以使用:
type Recursive = {p: Recursive} | {[p: string]: Recursive} | {[Key in 'a']: Recursive}
这就是检查第二个示例类型(带有索引签名)的原因。
TypeScript 3.7 扩展了对递归引用的支持,如 PR:
中所述- 泛型实例化 class 和接口类型(例如
Array<Foo>
)。 - 数组类型(例如
Foo[]
)。 - 元组类型(例如
[string, Foo?]
)。
所以现在,这三个例子也是有效的:
type RecursiveCI = Promise<RecursiveCI>
type RecursiveT = [number, boolean, RecursiveT]
type RecursiveA = RecursiveA[]
我假设该示例只是测试代码,但您可以使用像这样的辅助界面对其进行类型检查:
type StringOrRecordOfStrings = string | string[] | Record<string, RecordInterface>
interface RecordInterface extends Record<string, StringOrRecordOfStrings> {}