在 Typescript 世界中,我想知道如何向 createView 函数添加正确的类型,以便它根据传递函数的参数验证参数?
type ViewFn = (...args: any) => any;
function createView(view: ViewFn, data: Object) : any {
// how to validate data parameter
return true;
}
// test cases
function ViewA(data: { input: string }) {
return function() { return 'view A'; }
}
function ViewB(data: { input: boolean }) {
return function() { return 'view B'; }
}
createView(ViewA, { input: 'some' }); // ok
createView(ViewA, { validate_me: 'some' }); // expect error
createView(ViewB, { input: true }); // ok
createView(ViewB, { input: 'some' }); // expect error
createView(ViewB, { validate_me: 'some' }); // expect error
最佳答案
在提供的代码片段中,您没有引用该参数。该参数需要命名,例如 T
。然后, data
的类型可以是T
,以及 view
的类型可以是ViewFn<T>
.
从这里开始,TypeScript 将处理剩下的事情,因为它可以推断 data
之间的连接。 view
中收到的函数参数参数和 data
createView
的对象功能。
type ViewFn<T> = (data?: T) => () => string;
function createView<T>(view: ViewFn<T>, data?: T): boolean {
return true;
}
在此示例中,我们声明了 generic type T
在 createView
function,然后声明view
中接收到的函数的属性参数与此 T
匹配类型。同样,data
参数也匹配 T
类型。因此,data
ViewA
的参数view
中收到的函数完全对应于data
传递到createView
功能。
以下是经过更改的更新后的代码:
type ViewFn<T> = (data?: T) => () => string; // Declare viewFn (A and B) type of arguments and return
// Declare view: as viewFn, data as argument of view
function createView<T>(view: ViewFn<T>, data?: T): boolean {
return true;
}
function ViewA(data: { input: string }) {
return function () {
return 'view A';
};
}
function ViewB(data: { input: boolean }) {
return function () {
return 'view B';
};
}
// Test Cases
createView(ViewA, { input: 'something' }); // OK
createView(ViewA, { validate_me: 'something' }); // Error: Argument of type '{ validate_me: string; }' is not assignable to parameter of type '{ input?: string | undefined; }'.
createView(ViewB, { input: true }); // OK
createView(ViewB, { input: 'something' }); // Error: Argument of type '{ input: string; }' is not assignable to parameter of type '{ input?: boolean | undefined; }'.
createView(ViewB, { validate_me: 'something' }); // Error: Argument of type '{ validate_me: string; }' is not assignable to parameter of type '{ input?: boolean | undefined; }'.
createView((data: { input: 'something' }) => () => 'view C', { input: 'something' }); // OK
// Updated Test Cases (not working this solution, just with updated)
// New Test Cases
createView(() => () => 'view C', { input: 'something' }); // OK, but need - Error: Argument of type '{ input: 'something'; }' is not assignable to parameter of type '{ input: undefined; }'.
已更新(需要使用 extends conditional type
)
当 view
时,到目前为止概述的代码可以完美运行。 createView()
的属性是对象类型并且不是未定义的或空的。所以,当检查data
时createView()
的属性,我们需要确保该对象存在。我们可以通过添加 extends
来实现此目的情况。
type ViewFnData<T, D> = { [key in keyof D]: key extends keyof T ? T[key] : undefined }
声明data
如D
的createView(view, data)
与 data
类似的对象如T
的view(data)
。如果D
具有 T
中未声明的属性然后将类型设置为 undefined
,否则如果存在此键,则从 T
获取原始类型.
type ViewFn<T> = (data: T) => () => string; // Declare viewFn (A and B) type of arguments and return
type ViewFnData<T, D> = { [key in keyof D]: key extends keyof T ? T[key] : undefined } // Declare the type of the data object in the createView function, ensuring that the key-value pairs only include keys that exist in the T type and the values are either the corresponding values from T or undefined if the key is not present in the T type
// Declare T and D generic types (two unique types)
// where first given argument type is T and second given argument is D
// use T and D arguments to define really types what we enabled
// - view: viewFn<T>
// - data: viewFnData<T, D>
function createView<T, D>(view: ViewFn<T>, data?: ViewFnData<T, D>): boolean {
return true;
}
// New Test Cases
createView(() => () => 'view C', { input: 'something' }); // Error: Argument of type '{ input: 'something'; }' is not assignable to parameter of type '{ input: undefined; }'.
createView(() => () => 'view C'); // OK (if createView()'s data is just optional)
type ViewFn<T> = (data: T) => () => string; // Declare viewFn (A and B) type of arguments and return
type ViewFnData<T, D> = { [key in keyof D]: key extends keyof T ? T[key] : undefined } // Declare the type of the data object in the createView function, ensuring that the key-value pairs only include keys that exist in the T type and the values are either the corresponding values from T or undefined if the key is not present in the T type
// Declare view: as viewFn, data as argument of view
function createView<T, D>(view: ViewFn<T>, data?: ViewFnData<T, D>): boolean {
return true;
}
function ViewA(data: { input: string }) {
return function () {
return 'view A';
};
}
function ViewB(data: { input: boolean }) {
return function () {
return 'view B';
};
}
// Test Cases
createView(ViewA, { input: 'something' }); // OK
createView(ViewA, { validate_me: 'something' }); // Error: Argument of type '{ validate_me: string; }' is not assignable to parameter of type '{ input?: string | undefined; }'.
createView(ViewB, { input: true }); // OK
createView(ViewB, { input: 'something' }); // Error: Argument of type '{ input: string; }' is not assignable to parameter of type '{ input?: boolean | undefined; }'.
createView(ViewB, { validate_me: 'something' }); // Error: Argument of type '{ validate_me: string; }' is not assignable to parameter of type '{ input?: boolean | undefined; }'.
createView((data: { input: 'something' }) => () => 'view C', { input: 'something' }); // OK
createView(() => () => 'view C', { input: 'something' }); // Error: Argument of type '{ input: 'something'; }' is not assignable to parameter of type '{ input: undefined; }'.
createView(() => () => 'view C'); // OK (if createView()'s data is just optional)
关于typescript - 自定义 Prop 在 typescript 中验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76636915/