首页 > 解决方案 > 键入一个 prop 以接受一个接口或另一个接口

问题描述

我有一个函数可以发送请求以使用单个输入道具创建和编辑待办事项。我想输入此函数的输入以仅接受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'

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

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
}

标签: reactjstypescriptconditional-types

解决方案


我不会在这里推荐条件类型。您正在处理的是“受歧视的工会”。您有一个可以是 anICreateTodoInput或 an的类型IEditTodoInput,您需要知道它是哪一个,然后才能将其用于创建或编辑操作。

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

编辑:我试过 ICreateTodoInput | IEditTodoInput 但这是两种类型的联合,会给出错误 属性 'todoId' 在类型 'ICreateTodoInput' 上不存在

除非在联合的所有分支中声明,否则不能访问联合类型的属性。但是您可以 使用in运算符来缩小类型

interface ITodoMutatorProps {
    todoInput: ICreateTodoInput | IEditTodoInput;
}

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

TypeScript Playground 链接

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

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);
    }
}

推荐阅读