键入一个 prop 以接受一个接口或另一个接口

Type a prop to accept either one interface or another interface

我有一个功能可以发送请求以使用单个输入道具创建和编辑待办事项。 我想键入此函数的输入以仅接受 CreateTodoInputEditTodoInput

export interface ICreateTodoInput {
  todoName: string;
  todoType: TodoType;
  todoContent:string;
  todoCompletionStatus: TodoCompletionStatus;
}
export interface IEditTodoInput {
  todoId: string;
  todoName?: string;
  todoType?: TodoType;
  todoContent?: string;
  todoCompletionStatus?: TodoCompletionStatus;
}
//(the `Todo...` types are just string enums)

编辑:我试过 ICreateTodoInput | IEditTodoInput 但这是两种类型的结合,会出错 Property 'todoId' does not exist on type 'ICreateTodoInput'

文档提到了条件类型,这听起来像我想要的,但不确定如何将其添加到我的 React 组件中

type EitherOr<T> = T extends ICreateTodoInput
  ? ICreateTodoInput
  : IEditTodoInput;//will this work?

有问题的组件

interface ITodoMutatorProps{
todoInput?: //<-- want to type this
}

export const TodoMutator = ({
  todoInput 
}: ITodoMutatorProps): JSX.Element => {
//if todoInput is type ICreateTodoInput 
    //send create request

//if todoInput is type IEditTodoInput 
    //send edit request
}

我不会在这里推荐条件类型。您正在处理的是“discriminated union”。您的类型可以是 ICreateTodoInputIEditTodoInput,您需要先知道它是哪一种,然后才能将其用于创建或编辑操作。

区分这两种类型的最简单方法是查找 todoId 属性,它出现在 IEditTodoInput 中,但不出现在 ICreateTodoInput 中。 TypeScript 知道如果这个 属性 存在那么你的 todoInput 变量是一个 IEditTodoInput.

Edit: I have tried ICreateTodoInput | IEditTodoInput but that is a union of the two types and will give errors Property 'todoId' does not exist on type 'ICreateTodoInput'

除非在联合的所有分支中都声明了联合类型,否则您无法访问联合类型的 属性。但是你可以use the in operator to narrow the type.

interface ITodoMutatorProps {
    todoInput: ICreateTodoInput | IEditTodoInput;
}

export const TodoMutator = ({
    todoInput
}: ITodoMutatorProps): JSX.Element => {
    if ("todoId" in todoInput) {
        editTodo(todoInput);
    }
    else {
        createTodo(todoInput);
    }

TypeScript Playground Link

完整代码(枚举和函数的空占位符):

enum TodoCompletionStatus { }

enum TodoType { }

function editTodo(input: IEditTodoInput) { }

function createTodo(input: ICreateTodoInput) { }

export interface ICreateTodoInput {
    todoName: string;
    todoType: TodoType;
    todoContent: string;
    todoCompletionStatus: TodoCompletionStatus;
}

export interface IEditTodoInput {
    todoId: string;
    todoName?: string;
    todoType?: TodoType;
    todoContent?: string;
    todoCompletionStatus?: TodoCompletionStatus;
}

interface ITodoMutatorProps {
    todoInput: ICreateTodoInput | IEditTodoInput;
}

export const TodoMutator = ({
    todoInput
}: ITodoMutatorProps): JSX.Element => {
    if ("todoId" in todoInput) {
        //todoInput is type IEditTodoInput 
        //send edit request
        editTodo(todoInput);
    }
    else {
        //todoInput is type ICreateTodoInput 
        //send create request
        createTodo(todoInput);
    }
}