打字稿:如何编写一个类型保护来判断一个值是否是一个联合的成员?

时间:2018-06-09 06:24:58

标签: typescript

我有一个这样定义的类型:

let value1 = "thinga";
let value2 = "otherthing";

console.log("value1: " +  value1 <is in> Thing ); 
console.log("value2: " +  value2 <is in> Thing ); 

有没有办法可以判断我拥有的任意字符串值是否属于该联合的一部分?

Thing

我希望它对于value1是真的,但对于value2则是false。 实际的用例是有一个字符串数组,如果它们不在定义中(并且可能是日志),然后转换为正确的类型,我想要过滤掉它。

皱纹是keyof类型是生成的代码,用我的代码编译而且值可以改变 - 所以我不想在硬编码到值的类型保护中编写条件逻辑。我无法控制生成代码的东西 - 否则我猜测在这种情况下,如果类型是字符串枚举,我想做的事情会很容易。

我希望我能写一些使用protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); 或类似内容的打字机吗?但我无法看到如何使其发挥作用。

打字稿版本是2.8.1,虽然升级不是一个大问题。

我知道这个问题:https://stackoverflow.com/a/50085718/924597,但我不认为这是重复的,因为我不能在这个问题上使用答案。

1 个答案:

答案 0 :(得分:0)

在运行时无法访问字符串文字类型的并集中的值,因为所有类型信息都在编译时被擦除。我们可以使用这样的方式构造一个数组,如果联合类型确实改变,将导致编译时错误。

export type Thing = "thinga" | "thingb"
function getAllValues<T>()  {
    class Helper<TOriginal, TLeft extends TOriginal> {
        private data: TOriginal[] = [] ;
        private dummy!: TLeft;
        done<TThis extends Helper<any, never>>(this: TThis) : TOriginal[]{
            return this.data;
        }
        push<TValue extends TLeft>(value: TValue) : Helper<TOriginal, Exclude<TLeft, TValue>> {
            this.data.push(value);
            return this as any;
        }
    }

    return new Helper<T, T>();
}

let allValues = getAllValues<Thing>().push("thinga").push("thingb").done(); //Ok
let oldValues = getAllValues<Thing>().push("thinga").push("thingb").push("oldThing").done(); // error oldThinig is not part of the union
let missingValues = getAllValues<Thing>().push("thinga").done(); // error we are missing a value

现在我们拥有了所有的值,创建一个类型保护很简单:

const isThing = (function(){
    let allValues = getAllValues<Thing>().push("thinga").push("thingb").done();
    return function(s: string) : s is Thing {
        return allValues.indexOf(s as Thing) != -1; 
    }
})()

let value1 = "thinga";
let value2 = "otherthing";
console.log("value1: " + isThing(value1) ); 
console.log("value2: " + isThing(value2) );