typescript - Typescript如何在父函数上使用`unknown`类型来确定子函数的类型?
问题描述
我希望能够确定myValue
对应的接口。鉴于以下情况,我如何记录a
或b
取决于返回值testZero()
?
export interface ITest {
id: string
isLatest: boolean
createdAt: number
updatedAt: number
}
export interface ITestTwo {
id: string
isLatest: boolean
createdAt: string // This value was changed for this example
updatedAt: number
}
function testZero(): unknown {
return {
id: '123',
isLatest: true,
createdAt: '123',
updatedAt: 456
}
}
function testOne(): ITest | ITestTwo {
const myValue = testZero()
// THE FOLLOWING `IF` STATEMENT DOES NOT WORK AND IS WHAT I AM TRYING TO SOLVE
if (typeof t === typeof ITest) {
console.log('a')
} else if (typeof myValue === typeof ITestTwo) {
console.log('b')
}
}
testOne()
解决方案
您将需要编写运行时代码来检查值是否符合接口。当 TypeScript 代码编译为 JavaScript 时,TypeScript 接口本身会被删除。TypeScript 类型系统旨在在运行时描述类型;它不影响运行时间。所以ITest
并ITestTwo
不会在附近检查。
此外,运行时运typeof
算符将检查其操作数的类型并返回一小组字符串值中的一个;typeof myValue
就您而言,无论如何,您都可以期望"object"
。所以你不能typeof
用来检查myValue
自己。充其量你需要检查myValue
的属性并使用typeof
它们。
一种方法是编写一些类型保护函数来以编译器识别为类型检查的方式表示此运行时检查。对于“简单”对象类型,您可以使用运行时运typeof
算符检查每个属性,您可以编写一个通用检查函数,然后根据您的需要对其进行专门化。广义函数:
type TypeofMapping = {
string: string;
boolean: boolean;
number: number;
object: object;
undefined: undefined;
}
const simpleObjGuard = <T extends { [K in keyof T]: keyof TypeofMapping }>
(obj: T) => (x: any): x is { [K in keyof T]: TypeofMapping[T[K]] } => typeof x === "object" && x &&
(Object.keys(obj) as Array<keyof T>).every(k => k in x && typeof x[k] === obj[k]);
然后您可以将其专门用于ITest
and ITestTwo
:
const isITest: (x: any) => x is ITest =
simpleObjGuard({ id: "string", isLatest: "boolean", createdAt: "number", updatedAt: "number" });
const isITestTwo: (x: any) => x is ITestTwo =
simpleObjGuard({ id: "string", isLatest: "boolean", createdAt: "string", updatedAt: "number" });
所以该isITest()
函数将检查其参数是否与 兼容ITest
,并且该isITestTwo()
函数将检查其参数是否与 兼容ITestTwo
。在任何一种情况下,编译器都会将true
结果解释为可以将参数从 缩小unknown
到您正在检查的类型的证据:
function testOne(): ITest | ITestTwo {
const myValue = testZero()
if (isITest(myValue)) {
console.log("a "+myValue.createdAt.toFixed())
return myValue;
} else if (isITestTwo(myValue)) {
console.log("b "+myValue.createdAt.toUpperCase())
return myValue;
}
throw new Error("Guess it wasn't one of those");
}
console.log()
和return
行不会导致编译器错误的事实表明编译器将myValue
其视为缩小类型。在运行时,您可以检查它是否也可以工作:
testOne() // b 123
那里有一些库可以为你编写这些类型保护函数......我认为io-ts
它可以做到这一点,并以一种与 TypeScript 编译器很好地配合的方式制作序列化/反序列化代码。或者你可以自己写,就像simpleObjGuard
上面一样。
好的,希望有帮助;祝你好运!
推荐阅读
- javascript - 基于来自父级的道具反应动态导入
- microsoft-graph-api - office365 Graph API 仅列出管理员用户
- javascript - 如何在不重定向的反应路由器链接中创建按钮组件?
- r - 无法在 R 中加载 devtools 包?
- linear-algebra - 在线性系统 A*x=b 中,如何从给定的 x 和 b 获得 A,在 SymPy 中象征性地
- python - on Heroku how can I get the current release number of my app
- laravel - Nullable 和 Unique 不适用于 laravel 验证
- c - 有 N 个朋友,每个人都有 A[i] 数量的钱。检查是否可以在所有人之间分配相等的钱。给C代码
- python - 如何在阅读文档中添加电子表格?
- jquery - 横幕效果不好