Typescript参数类型约束

场景需求:

最近在写库的时候,遇到了这么一个需求,我想限制调用者参数输入,首先有这么一个方法,接收两个参数,第二个参数根据第一参数来变化。

先看代码

class Subscription{
    type:string;
    topic: string;

    constructor(type: string, topic: string) {
        this.type = type;
        this.topic = topic;
    }
}

好的,首先有一个订阅类,构造方法接受type和topic两个参数。

看参数,订阅有分类型,类型又有主题

事件推送:{type:"EVENT",topic:"*"}
系统推送-ping:{type:"SYSTEM",topic:"ping"}
系统推送-disconnect:{type:"SYSTEM",topic:"disconnect:"}
回调推送-robot:{type:"CALLBACK",topic:"robot"}
回调推送-card:

需求明确:需要在type为"EVENT"的时候,topic只能输入"*",type为"SYSTEM"时,topic只能输入"ping"和"disconnect"

代码实现

先定义订阅类型

type SubscriptionType = "SYSTEM" | "EVENT" | "CALLBACK";

将订阅类型作为属性,topic作为类型,一一映射

type Topics = {
    SYSTEM: "ping" | "disconnect";
    EVENT: "*";
    CALLBACK: "robot" | "card";
};

构造函数私有化,创建create泛型方法供外部调用

class Subscription {
    readonly type: SubscriptionType;
    readonly topic: string;

    private constructor(type: SubscriptionType, topic: string) {
        this.type = type;
        this.topic = topic;
    }

    static create<T extends SubscriptionType>(type: T, topic: Topics[T]) {
        return new Subscription(type, topic);
    }
}

测试
image

感觉还可以,但是type的类型好像有点多余了,再进一步优化

//删除SubscriptionType
// type SubscriptionType = "SYSTEM" | "EVENT" | "CALLBACK";

type Topics = {
    SYSTEM: "ping" | "disconnect";
    EVENT: "*";
    CALLBACK: "robot" | "card";
};

//修改type类型为string
export class Subscription {
    readonly type: string;
    readonly topic: string;

    private constructor(type: string, topic: string) {
        this.type = type;
        this.topic = topic;
    }
	// 修改泛型方法
    static create<T extends keyof Topics, K extends Topics[T]>(type: T, topic: K) {
        return new Subscription(type, topic);
    }
}

到这感觉更OK了,测试好用!
image

还没完,原理搞明白了,不想调用create方法,只想通过new的方式。
那就继续优化,直接将泛型约束作用到类上。

export class Subscription<T extends keyof Topics, K extends Topics[T]> {
    readonly type;
    readonly topic;

    constructor(type: T, topic: K) {
        this.type = type;
        this.topic = topic;
    }
};

依然好用
image

总结

主要依靠了Typescript的泛型功能,加上keyof运算符来和索引类型来实现我们想要的效果。extends关键字可以确保不会获取其他属性。
得以于Typescript强大的泛型系统,想要实现这种效果还有其他的方式,其思想是一样的,我这里就不再一一列举了。

posted on 2024-06-11 23:16  luyifo  阅读(23)  评论(0)    收藏  举报

导航