将通用类型 T 缩小为 Pick<T, U> 的类型保护
Type guard which narrows generic type T to Pick<T, U>
我有一个类型保护,其唯一目的是检查对象中 属性 的存在以及它是否具有一些价值。
对于类型系统我想对编译器说这句话,如果类型保护检查成功:
This is an input object, if type guard succeeds then output is an object
with lineHeight property
对于确切的对象,它看起来像这样:
type PickedLineHeight = Pick<TextStyle, "lineHeight">
type NonNullableLineHeight = Required<PickedLineHeight>
function hasLineHeight(style: object): style is NonNullableLineHeight {
return (
style.hasOwnProperty("lineHeight") &&
(style as PickedLineHeight).lineHeight !== undefined
)
}
我如何开发更通用的函数版本,例如 hasProperty(style, prop)?
我的尝试是:
function hasProperty<T extends { [key: string]: any}, U extends keyof T>(style: T, prop: U): style is Pick<T, U> {
return (
style.hasOwnProperty(prop) &&
style[prop] !== undefined
)
}
但我不断收到此错误消息,我无法消除或理解
无意间想到了这个解决方案,我个人认为,与显示错误的相同。
但无论如何,这是毫无怨言的工作:
function hasProperty<T extends object>(style: T, prop: keyof T): style is Pick<T, typeof prop> {
return (
style.hasOwnProperty(prop) &&
style[prop] !== undefined
)
}
function hasFontSize(style: TextStyle) {
return hasProperty(style, "fontSize")
}
function hasLineHeight(style: TextStyle) {
return hasProperty(style, "lineHeight")
}
我可能会这样输入 hasProperty()
:
function hasProperty<T extends object, K extends keyof T>(
style: T,
prop: K
): style is T & { [P in K]-?: Exclude<T[K], undefined> } {
return style.hasOwnProperty(prop) && style[prop] !== undefined;
}
这应该反映出 hasProperty()
将验证 属性 是否存在而不是 undefined
。受保护的类型 T & { [P in K]-?: Exclude<T[K], undefined> }
可分配给 T
(这是 intersection T & ...
所说的)并且对 K
键控 属性.注意,{ [P in K]-?: Exclude<T[K], undefined> }
也可以写成Required<Record<K, Exclude<T[K], undefined>>
,这样更容易理解。让我们确保它的行为符合预期:
interface Example {
required: string;
optional?: string;
requiredButPossiblyUndefined: string | undefined;
requiredButPossiblyNull: string | null;
}
function checkExample(ex: Example) {
ex.required.toUpperCase(); // okay
// hasProperty de-optionalizes optional properties
ex.optional.toUpperCase(); // error, possibly undefined
if (hasProperty(ex, "optional")) {
ex.optional.toUpperCase(); // okay
}
// hasProperty removes undefined from list of possible values
ex.requiredButPossiblyUndefined.toUpperCase(); // error, possibly undefined
if (hasProperty(ex, "requiredButPossiblyUndefined")) {
ex.requiredButPossiblyUndefined.toUpperCase(); // okay
}
// hasProperty doesn't do anything with null
ex.requiredButPossiblyNull.toUpperCase(); // error, possibly null
if (hasProperty(ex, "requiredButPossiblyNull")) {
ex.requiredButPossiblyNull.toUpperCase(); // error, possibly null
}
}
看起来不错。好的,希望有帮助。祝你好运!
我有一个类型保护,其唯一目的是检查对象中 属性 的存在以及它是否具有一些价值。
对于类型系统我想对编译器说这句话,如果类型保护检查成功:
This is an input object, if type guard succeeds then output is an object with lineHeight property
对于确切的对象,它看起来像这样:
type PickedLineHeight = Pick<TextStyle, "lineHeight">
type NonNullableLineHeight = Required<PickedLineHeight>
function hasLineHeight(style: object): style is NonNullableLineHeight {
return (
style.hasOwnProperty("lineHeight") &&
(style as PickedLineHeight).lineHeight !== undefined
)
}
我如何开发更通用的函数版本,例如 hasProperty(style, prop)?
我的尝试是:
function hasProperty<T extends { [key: string]: any}, U extends keyof T>(style: T, prop: U): style is Pick<T, U> {
return (
style.hasOwnProperty(prop) &&
style[prop] !== undefined
)
}
但我不断收到此错误消息,我无法消除或理解
无意间想到了这个解决方案,我个人认为,与显示错误的相同。
但无论如何,这是毫无怨言的工作:
function hasProperty<T extends object>(style: T, prop: keyof T): style is Pick<T, typeof prop> {
return (
style.hasOwnProperty(prop) &&
style[prop] !== undefined
)
}
function hasFontSize(style: TextStyle) {
return hasProperty(style, "fontSize")
}
function hasLineHeight(style: TextStyle) {
return hasProperty(style, "lineHeight")
}
我可能会这样输入 hasProperty()
:
function hasProperty<T extends object, K extends keyof T>(
style: T,
prop: K
): style is T & { [P in K]-?: Exclude<T[K], undefined> } {
return style.hasOwnProperty(prop) && style[prop] !== undefined;
}
这应该反映出 hasProperty()
将验证 属性 是否存在而不是 undefined
。受保护的类型 T & { [P in K]-?: Exclude<T[K], undefined> }
可分配给 T
(这是 intersection T & ...
所说的)并且对 K
键控 属性.注意,{ [P in K]-?: Exclude<T[K], undefined> }
也可以写成Required<Record<K, Exclude<T[K], undefined>>
,这样更容易理解。让我们确保它的行为符合预期:
interface Example {
required: string;
optional?: string;
requiredButPossiblyUndefined: string | undefined;
requiredButPossiblyNull: string | null;
}
function checkExample(ex: Example) {
ex.required.toUpperCase(); // okay
// hasProperty de-optionalizes optional properties
ex.optional.toUpperCase(); // error, possibly undefined
if (hasProperty(ex, "optional")) {
ex.optional.toUpperCase(); // okay
}
// hasProperty removes undefined from list of possible values
ex.requiredButPossiblyUndefined.toUpperCase(); // error, possibly undefined
if (hasProperty(ex, "requiredButPossiblyUndefined")) {
ex.requiredButPossiblyUndefined.toUpperCase(); // okay
}
// hasProperty doesn't do anything with null
ex.requiredButPossiblyNull.toUpperCase(); // error, possibly null
if (hasProperty(ex, "requiredButPossiblyNull")) {
ex.requiredButPossiblyNull.toUpperCase(); // error, possibly null
}
}
看起来不错。好的,希望有帮助。祝你好运!