为什么 Partial<(param1: ParamType, ...) => ReturnType> 表现得像 any?
Why Partial<(param1: ParamType, ...) => ReturnType> behaves like any?
为什么这段代码可以编译?
const fn: Partial<(a: string) => number> = "LOL DIS IS A STRING"; // any non-null value
// Though this won't compile under strict null checks:
const fn: Partial<(a: string) => number> = null;
const fn: Partial<(a: string) => number> = undefined;
将 DeepPartial
应用于具有方法的类型时会出现此问题。
简答:Partial<(a: string) => number>
计算结果为 {}
,空对象类型,类似于 unknown
,但排除了 null
和 undefined
。
更长的答案:
Partial<T>
是定义为 {[K in keyof T]?: T[K]}
的 mapped type。它遍历 T
的属性并使它们中的每一个都是可选的。但是,在这种情况下,keyof ((a: string)=>number)
是 never
;它没有属性。 (好吧,函数类型 do 具有来自 Function
接口的属性,例如 bind
、call
、length
等,和 Object
接口的属性,例如 toString
和 valueOf
等。但是这些属性通常对迭代没有用,所以它们被抑制了。)所以 Partial<(a: string)=>number>
returns 没有属性的对象类型:空类型 {}
.
空类型 {}
的行为几乎与 unknown
, in that nearly everything is assignable to it 类似。这是因为 TypeScript 中的对象类型是 "open",您可以向类型添加 属性 而不会使其不兼容。因此在
interface Foo {a: string}
interface Bar extends Foo {b: string}
Bar
类型 ({a: string, b: string}
) 的值也可以分配给 Foo
类型 ({a: string}
)。如果您得出其合乎逻辑的结论,那么任何对象类型都可以分配给空对象类型 {}
。此外,如果 string
和 number
等基本类型的属性兼容,则认为它们可分配给对象类型。由于 string
和 number
类型确实具有属性(如 length
和 toFixed
等),它们也可以分配给空对象类型。当您尝试从中读取属性时,只有 null
和 undefined
实际上会抛出运行时错误,因此这两个值不被视为可分配给 {}
。
如果你想做递归映射类型,你应该决定当你点击一个函数类型 属性 时你希望看到什么,然后使用 conditional type 来实现发生。显而易见的事情就是保持方法函数类型不变(尽管方法的 presence 应该是可选的?不确定。)
所以看起来像
type DeepPartial2<T> = T extends Function ? T : {
[K in keyof T]?: DeepPartial2<T[K]>
}
interface Foo {
name: string,
age: number,
yell(): void,
friend: Foo
}
type DPFoo = DeepPartial2<Foo>;
/*
type DPFoo = {
name?: string | undefined;
age?: number | undefined;
yell?: (() => void) | undefined;
friend?: DPFoo | undefined;
}
*/
好的,希望对你有帮助;祝你好运!
为什么这段代码可以编译?
const fn: Partial<(a: string) => number> = "LOL DIS IS A STRING"; // any non-null value
// Though this won't compile under strict null checks:
const fn: Partial<(a: string) => number> = null;
const fn: Partial<(a: string) => number> = undefined;
将 DeepPartial
应用于具有方法的类型时会出现此问题。
简答:Partial<(a: string) => number>
计算结果为 {}
,空对象类型,类似于 unknown
,但排除了 null
和 undefined
。
更长的答案:
Partial<T>
是定义为{[K in keyof T]?: T[K]}
的 mapped type。它遍历T
的属性并使它们中的每一个都是可选的。但是,在这种情况下,keyof ((a: string)=>number)
是never
;它没有属性。 (好吧,函数类型 do 具有来自Function
接口的属性,例如bind
、call
、length
等,和Object
接口的属性,例如toString
和valueOf
等。但是这些属性通常对迭代没有用,所以它们被抑制了。)所以Partial<(a: string)=>number>
returns 没有属性的对象类型:空类型{}
.空类型
{}
的行为几乎与unknown
, in that nearly everything is assignable to it 类似。这是因为 TypeScript 中的对象类型是 "open",您可以向类型添加 属性 而不会使其不兼容。因此在interface Foo {a: string} interface Bar extends Foo {b: string}
Bar
类型 ({a: string, b: string}
) 的值也可以分配给Foo
类型 ({a: string}
)。如果您得出其合乎逻辑的结论,那么任何对象类型都可以分配给空对象类型{}
。此外,如果string
和number
等基本类型的属性兼容,则认为它们可分配给对象类型。由于string
和number
类型确实具有属性(如length
和toFixed
等),它们也可以分配给空对象类型。当您尝试从中读取属性时,只有null
和undefined
实际上会抛出运行时错误,因此这两个值不被视为可分配给{}
。
如果你想做递归映射类型,你应该决定当你点击一个函数类型 属性 时你希望看到什么,然后使用 conditional type 来实现发生。显而易见的事情就是保持方法函数类型不变(尽管方法的 presence 应该是可选的?不确定。)
所以看起来像
type DeepPartial2<T> = T extends Function ? T : {
[K in keyof T]?: DeepPartial2<T[K]>
}
interface Foo {
name: string,
age: number,
yell(): void,
friend: Foo
}
type DPFoo = DeepPartial2<Foo>;
/*
type DPFoo = {
name?: string | undefined;
age?: number | undefined;
yell?: (() => void) | undefined;
friend?: DPFoo | undefined;
}
*/
好的,希望对你有帮助;祝你好运!