【问题标题】:Typescript: How to write a type guard to tell if a value is a member of a union?Typescript:如何编写类型保护来判断一个值是否是联合的成员?
【发布时间】:2018-06-09 15:28:47
【问题描述】:

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

export type Thing = "thinga" | "thingb"

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

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

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

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

问题在于 Thing 类型是生成的代码,它与我的代码一起编译并且值可以更改 - 所以我不想在硬编码到值的类型保护中编写条件逻辑。我不控制生成代码的东西 - 否则我猜在这种情况下,如果类型是字符串枚举,我想做的事情会很容易。

我希望我可以编写某种使用keyof 或类似内容的类型保护?但我看不出如何使它工作。

Typescript 版本是 2.8.1,不过升级不是什么大问题。

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

【问题讨论】:

  • 你可以在接口上定义键,然后使用keyof interfacename作为类型保护,如果你知道键

标签: typescript


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 2022-11-22
    • 2012-06-07
    • 1970-01-01
    • 2019-02-13
    • 2013-08-19
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多