穷举检查没有明确的字符串

时间:2017-08-24 14:05:00

标签: javascript typescript

在函数末尾分配(或断言)never是一种在Typescript中使用的技术,以便在编译时强制进行穷举检查。

然而,要使编译器检测到这一点,它需要检查显式字符串,以确定函数在never的赋值/断言之前是否明确返回。

是否有可能引入某种类型的Object.freeze变体,它只适用于对象文字,并进一步向上链,以便可以完成以下内容?

更好的是,有没有办法创建一个界面,其中的键自动是每个的Action.type(在本例中)?如果是这种情况 - actionMap可以简单地声明为该接口,这将强制在编译时进行检查。

两者都是同一问题的解决方案......只给出一个有区别的联合,是否可以在编译时进行这样的详尽检查,而不需要在函数中使用显式字符串?

interface Increment {
    type: 'increment'
}

interface Decrement {
    type: 'decrement'
}

type Action = Increment | Decrement

const inc: Increment = { type: 'increment' };
const dec: Decrement = { type: 'decrement' };

//this would be a typescript variation
const actionMap = Object.freeze({
    [inc.type]: n => n + 1,
    [dec.type]: n => n-1
});


function doAction(action: Action, val: number): number {

    if(actionMap[action.type]) {
        return actionMap[action.type](val);
    }

    //this would error at compile time if the above checked failed 
    const _exhaustiveCheck: never = action;
}

console.log(doAction(inc, 1));
console.log(doAction(dec, 1));

1 个答案:

答案 0 :(得分:3)

有一种相当直接的方法来制作一张地图,以确保它在一个有区别的联合中具有每个案例的值。您只需设置它以使其键的类型是区分的联合标识符。

type ActionMap = {
    [P in Action["type"]]: (val:number)=>number
}; 

然后,您可以实现此界面,如下所示:

var map: ActionMap = {
   decrement: n => n - 1,
   increment: n=> n + 1
}

编辑:在一堆乱七八糟的东西之后,我发现了一个更通用,功能更强大的解决方案,它不仅可以输入区分联合值的键,还可以输入有效负载。

首先:以key:type对的形式定义你的联合。 (我认为无论如何这都是更清晰的)

type Actions = {
    "increment": { incrementValue: number }
    "decrement": { decrementValue: number }
}

第二个:从该地图创建一个Action Disriminated Union。这不是世界上最清晰的代码,它为ActionsMap中的每个键值对做了什么,通过添加类型值{type:key}来创建新类型然后将所有这些类型相加以创建您的歧视联盟。

type Action = {
    [P in keyof Actions]: { type: P } & ActionsMap[P]
}[keyof Actions];

第三次:为地图创建一个类型

type ActionsMap = {
    [P in  keyof Actions]: (val:number,action:Actions[P])=>number
}

Forth :享受完全类型安全的动作/减速器地图!

const map:ActionsMap = {
    decrement: (val, action) => val + action.decrementValue,
    increment: (val, action) => val + action.incrementValue,
}

公平警告。这极大地限制了打字稿定义可以做什么,我个人已经被依赖于一些打字稿边缘行为而被咬,只是为了让它在下一个版本中被改变。