【问题标题】:Define a type in typescript with conditional properties / limits使用条件属性/限制在打字稿中定义类型
【发布时间】:2018-04-05 12:57:34
【问题描述】:

我是 typescript 的新手,并且已经学会了如何定义自定义类型,例如:

类型 T = {a:number, b:any}

是否可以使用类中定义的类型构造函数在 TypeScript 中为长度大于 2 的所有字符串的集合定义一个类型?

或者为所有大于 0 的数字的集合定义一个类型?

【问题讨论】:

  • 不行,你只能用any或其他数据类型声明一个变量,没有任何逻辑限制

标签: typescript types


【解决方案1】:

虽然您不能在编译时施加这种任意约束,但您可以创建强制用户调用执行这些验证的函数的类型,然后使用品牌类型在您的代码中依赖这些不变量

type PositiveNumber =  number & { positive: true}
type StringOfMinLength<T extends number> =  string & { minLegth: T}

type T = {a:PositiveNumber, b:StringOfMinLength<3> }

function isPositiveNumber(value: number): value is PositiveNumber {
    if( value < 0 ) return false
    return  true;
}
function asPositiveNumber(value: number) {
    if( !isPositiveNumber(value) ) throw new Error("Not ok")
    return value; // type guard above, value will now be a PositiveNumber 
}

function isStringOfMinLength<T extends number>(value: string, length: T): value is StringOfMinLength<T> {
    if( value.length < length ) return false;
    return true;
}

function asStringOfMinLength<T extends number>(value: string, length: T): StringOfMinLength<T> {
    if(!isStringOfMinLength(value, length) ) throw new Error("Not ok")
    return value; // type guard above, value will now be a PositiveNumber 
}

type MyData = {a:PositiveNumber, b:StringOfMinLength<3>}
let myObj: MyData = {
    a: asPositiveNumber(0),
    b: asStringOfMinLength("Test", 3),
}

Math.sqrt(myObj.a) // a will be greater then 0
myObj.b[2] // index will exist, length greater then 3

let myNotOkObject: MyData = {
    a: -1, // will be a compile error, the checking function is not called
    b: "Test" // this will also be an error event though it satisfies the constraint since we don't call the appropriate function
}

// we can also use the type guard version instead (is*) of the assertion version (as*)
let a = 10;
let b = "Test"
if(isPositiveNumber(a) && isStringOfMinLength(b, 3))
{
    let myOtherObj: MyData = { a, b } // a and b are PositiveNumber and respectively StringOfMinLength<3>
} else {
    // handle case when they are not what was expected
}

您可以在需要基本类型的任何地方使用品牌类型(例如Math.sqrt(myObj.a)),但不能将基本类型直接分配给品牌类型的字段。这在实际代码中是否有价值取决于您和您的用例。

这个article 有更多关于品牌类型的讨论。

编辑

添加了品牌类型创建函数的类型保护版本,这样您就可以检查不变量是否为真并自行处理错误情况,而不是抛出错误。 10 倍于 @AluanHaddad 的想法。

【讨论】:

  • 为什么不使用类型保护而不是抛出?这样您就不必使用类型断言,也不必分配结果。当然你的方法是完全有效的。
  • @AluanHaddad 当时我没有想到类型保护,但你说得对,函数的类型保护版本会非常有用。但是这两个版本都需要,throw 版本和类型保护版本,在某些情况下,仅资产值是有效的会更容易,否则会抛出错误,而在其他情况下,保护会更好。我将很快添加一个类型保护版本。这个想法的 10 倍 :-)
  • 好点。既然您提到了它,您就可以从 throwing 验证器中调用类型保护函数。这应该从类型保护推断验证器的结果类型,因为错误分支会抛出。那里有一些不错的代码重用:) 无论如何+1
  • @AluanHaddad 是的,这就是我打算这样做的方式,使验证器版本看起来也更好,没有断言:) 10x 再次
猜你喜欢
  • 2018-01-18
  • 1970-01-01
  • 1970-01-01
  • 2023-02-06
  • 2021-12-16
  • 2019-09-26
  • 1970-01-01
  • 1970-01-01
  • 2019-05-03
相关资源
最近更新 更多