使用条件属性/限制在打字稿中定义类型 [英] Define a type in typescript with conditional properties / limits

查看:27
本文介绍了使用条件属性/限制在打字稿中定义类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm new to typescript and have learned how to define a custom type like:

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

type T = {a:number, b:any}

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

Is it possible to define a type in TypeScript for the set of all strings with length larger than 2 using the type constructors defined in class?

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

or maybe define a type for the set of all numbers larger than 0?

推荐答案

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

While you can't impose such arbitrary constraint at compile time, you can create types that force the user to call a functions that performs these validations and then rely on these invariants in your code using branded type

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)),但您不能将基本类型直接分配给品牌类型的字段.这在实际代码中是否有价值取决于您和您的用例.

You can use a branded type anywhere the base type is required (ex Math.sqrt(myObj.a)) but you can't assign the base type directly to a field of the branded type. Whether this has value in real code is up to you and your use case.

这篇文章有更多内容关于品牌类型的讨论.

This article has a bit more of a discussion on branded types.

编辑

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

Added a type guard version of the branded type creation functions, that way you can check if an invariant is true and handle the false case on your own instead of having an error thrown. 10x to @AluanHaddad for the idea.

这篇关于使用条件属性/限制在打字稿中定义类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆