typescript - 自定义 Prop 在 typescript 中验证

标签 typescript

在 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 TcreateView 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() 的属性是对象类型并且不是未定义的或空的。所以,当检查datacreateView() 的属性,我们需要确保该对象存在。我们可以通过添加 extends 来实现此目的情况。

type ViewFnData<T, D> = { [key in keyof D]: key extends keyof T ? T[key] : undefined }

声明dataDcreateView(view, data)data 类似的对象如Tview(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/

相关文章:

node.js - 将 typedoc 部署到 gh-pages

typescript - 模式拼接通过添加前缀解决冲突

visual-studio - Visual Studio 2015 无法识别 typescript

javascript - Visual Studio 2017 无法更改 project.csproj 的 <TypescriptModuleKind> 以进行 typescript 转译

html - Angular5 mat-menu修改填充和宽度属性?

javascript - 如何使用angular7关闭api响应的ngx-dialog?

javascript - 如何在 typescript 中将 snake_case 转换为 camelcase?

javascript - 如何在 Angular2 中使用 chart.js?

javascript - TypeScript XAML 框架

typescript - 如何修复 Typescript linting 在 VSCode 中不起作用的问题?