我有一个数据 struct 来代表我的业务操作:

const operations = {
    list: {
        request: "a",
        response: "b",
    },
    get: {
        request: "a",
        response: "b",
    },
} as const;

我想创建一个函数,它将接受基于上面operations的回调:

type Ops = typeof operations;

type Callbacks = {
    [Property in keyof Ops]: (
        param: Ops[Property]["request"]
    ) => Ops[Property]["response"];
};

现在,如果我想定义我的回调,如果我错过了其中的任何一个,编译器都会抱怨:

const callbacks: Callbacks = {

};
// ^^^--- Type '{}' is missing the following properties from type 'Callbacks': list, get

现在我的问题是,我想创建另一个类型,以便我可以类型判断operations对象的 struct :

interface OperationDescriptor<A, B> {
    request: A;
    response: B;
}

type Operations = {
    [key: string]: OperationDescriptor<any, any>;
};

const operations: Operations = {
    list: {
        request: "a",
        response: "b",
    },
    get: {
        request: "a",
        response: "b",
    },
} as const; // okay

const badOperations: Operations = {
    list: {
        request: "a",
        response: "b",
    },
    get: { // error, missing response prop
        request: "a",        
    },
} as const; 

但当我这样做时,编译器将不再抱怨,因为Operations不知道我在operations中的键.有没有办法既有我的蛋糕又吃它,例如:

  • 定义一个类型,我可以用它来判断operations
  • 有一个Callbacks类型会根据operations的 struct 对我的回调函数进行类型判断?

推荐答案

您可以使用the satisfies operator判断值是否可分配给类型,而不使用widening将值分配给该类型.它是为type annotation会忘记你关心的信息的情况而设计的:

const operations = {
    list: {
        request: "a",
        response: "b",
    },
    get: {
        request: "a",
        response: "b",
    },
} as const satisfies Operations;

如果上面的内容被编译,那么你就知道你没事了.否则,你会得到你所期望的错误:

const badOperations = {
    list: {
        request: "a",
        response: "b",
    },
    get: { // error!
    //~ <-- Property 'response' is missing
        request: "a",
    },
} as const satisfies Operations;

而类型typeof operations仍然是完全如你所需要的那样详细:

type Ops = typeof operations;
/* type Ops = {
    readonly list: {
        readonly request: "a";
        readonly response: "b";
    };
    readonly get: {
        readonly request: "a";
        readonly response: "b";
    };
} */

Playground link to code

Typescript相关问答推荐

如何根据参数的值缩小函数内的签名范围?

如何从具有给定键列表的对象类型的联合中构造类型

在键和值为ARGS的泛型函数中未正确推断类型

为什么TypeScript假设文档对象始终可用?

TypeScrip:基于参数的条件返回类型

在MessageStore对象中实现条件类型时出现TypeScrip错误

ANGLE独立组件布线错误:没有ActivatedRouting提供程序

在另一个类型的函数中,编译器不会推断模板文字类型

使用2个派生类作为WeakMap的键

是否可以判断某个类型是否已合并为内部类型?

刷新页面时,TypeScrip Redux丢失状态

保护函数调用,以便深度嵌套的对象具有必须与同级属性函数cargument的类型匹配的键

如何从输入中删除值0

如何避免多个类型参数重复?

我可以将一个类型数组映射到TypeScrip中的另一个类型数组吗?

有没有一种方法可以提升对象的泛型级别,而对象的值是泛型函数?

类型脚本中函数重载中的类型推断问题

可以将JS文件放在tsconfig';s includes/files属性?或者,我如何让tsc判断TS项目中的JS文件?

元组解释

如何在Typescript 中定义具有相同类型的两个泛型类型的两个字段?