在运算符中使用的typescrtip字符串文字类型

时间:2018-07-06 11:07:25

标签: typescript

Hello Stack社区,
假设我定义了以下字符串文字:

type FormConstants = 'new' | 'edit';

现在我要检查值val是否等于FormConstants定义的值:

    function inSet(val: string): boolean {
      if ((val as FormConstants) === XXX ) {
        return true;
      } else {
        return false;
      }
    }

XXX是我要查找的语句。解决方案为:

  • keyof FormConstants
  • in FormConstants
  • typeof FormConstants

惨败,因为它们每个都使用FormConstants作为值,而FormConstants代表一种类型。

编辑: 而且我想避免肯定地使用汇总的switch / if-elseif-else来发布肯定声明

1 个答案:

答案 0 :(得分:2)

类型在运行时不存在,因此来自它们的任何信息只能指导编译时检查,而不能指导运行时行为。您可以选择以下几种方法之一:

使用字符串枚举,它是一种类型,也是一个运行时对象:

enum FormConstants { new = 'new', edit = 'edit' }

function inSet(val: string): boolean {
    if (Object.values(FormConstants).includes(val)) {
    return true;
    } else {
    return false;
    }
}

或者使用字符串文字数组构造一个值数组,并派生出FormConstants的形式,

function stringLilteralArray<T extends string>(values: T[]) : T[] {
    return values
}
const FormConstants = stringLilteralArray(['new', 'edit']) ;
type FormConstants = typeof FormConstants[number];

function inSet(val: string): boolean {
    if (FormConstants.includes(val as FormConstants)) {
    return true;
    } else {
    return false;
    }
}

如果字符串文字的并集不受您控制,则可以构造一个函数来构建所有值的数组,以确保您传递的值必须与联合中的值完全相同(编译器将强制执行此操作)。因此,即使您必须重复这些值,它们也不会出现差异:

type FormConstants = 'new' | 'edit';
function unionValues<T extends string>(values: { [P in T]: P}) : T[] {
    return Object.values(values);
}
const FormConstants = unionValues<FormConstants>({ new : 'new', edit :'edit' }) ;

function inSet(val: string): boolean {
    if (FormConstants.includes(val as FormConstants)) {
    return true;
    } else {
    return false;
    }
}

修改

上述方法的一种变体,不用数组,使用对象键,肯定会更快:

type FormConstants = 'new' | 'edit';
function unionValues<T extends string>(values: { [P in T]: true }) : typeof values {
    return values;
}
const FormConstants = unionValues<FormConstants>({ new : true, edit :true }) ;

function inSet(val: string): boolean {
    if (val in FormConstants) {
        return true;
    } else {
         return false;
    }
}