假设我在我的应用中定义了这种类型:
type PiiType = 'name' | 'address' | 'email';
我在应用程序周围使用此类型来强制进行一些强类型化。我们可能会从表面上表示PII的服务器上获取信息,并需要根据此类型定义检查PII的类型是否有效。
关于此问题的A previous solution建议使用第二个数组来复制有效值,并对照该数组的内容检查字符串:
type PiiType = 'name' | 'address' | 'email';
isValidPii(value: string): Boolean {
const piiTypeValues = ['name', 'address', 'email'];
return piiTypeValues.indexOf(potentialValue) !== -1;
}
这对我们来说是不可取的,因为它需要两次定义类型,删除单个事实来源,并可能导致错误。
如何在不重复定义的情况下根据此联合类型检查给定值是否有效?
例如,如果有一个像isoftype
这样的运算符,我可以这样使用它:
'name' isoftype PiiType; // true
'hamburger' isoftype PiiType; // false
100 isoftype PiiType; // false
...但是此运算符不存在,所以我不确定应该怎么做才能检查此类型的值是否有效。 instanceof
存在,但仅针对类/接口进行检查,并且typeof
仅返回JavaScript类型(例如string
或number
)。
我们正在考虑使用枚举代替此类型,但我想先检查一下是否可以使用本机类型做些什么。
答案 0 :(得分:3)
诀窍是通过一个标识函数来运行数组,该函数可以推断受string
约束的元素类型。这将导致编译器推断文字类型的并集:
function asLiterals<T extends string>(arr: T[]): T[] { return arr; }
const piiTypeValues = asLiterals(['name', 'address', 'email']);
type PiiType = (typeof piiTypeValues)[number];
还有另一种解决方法here,但是上面的方法似乎更简单。
答案 1 :(得分:2)
虽然复制并集不理想,但是我们可以使用编译器来验证并集和重复值是同步的。如果您无法控制工会,这是最安全的方法(否则@ Matt-McCutchen的解决方案是更好的方法)
我们可以利用映射类型和多余的对象文字属性检查来创建一个函数,该函数将采用与联合具有相同键的对象。对象的值无关紧要,我们只使用文字类型0
type PiiType = 'name' | 'address' | 'email';
function isValidBuilder<T extends string>(o: Record<T, 0>) {
let values = Object.keys(o)
return function (v: string): v is T {
return values.indexOf(v) !== -1
}
}
const isValidPii = isValidBuilder<PiiType>({
name: 0,
address: 0,
email:0
})
// Error missing key
const isValidPii2 = isValidBuilder<PiiType>({
name: 0,
address: 0,
})
//error excess key
const isValidPii4 = isValidBuilder<PiiType>({
name: 0,
address: 0,
email: 0
other:0
})