打字稿:如何使用结构子类型和继承

时间:2018-01-20 11:57:49

标签: typescript structural-typing

考虑以下Typescript类:

abstract class EnforcedString
{
    private minLength: number;
    private maxLength: number;
    private value: string;
    protected identifier: string;

    constructor(minLength: number, maxLength: number, identifier: string)
    {
        this.minLength = minLength;
        this.maxLength = maxLength;
        this.identifier = identifier;
    }

    public setValue(value: string): void
    {
        if (typeof value !== 'string') {
            throw(new Error(this.identifier + ' must be a valid string'));
        }        

        if (value.length > this.maxLength) {
            throw new Error(this.identifier + ' must have a maximum length of: ' + this.maxLength);
        }

        if (this.minLength > 0) {
            if (value.length < this.minLength) {
            const characterString = (this.minLength === 1) ? 'character' : 'characters';
            throw new Error(this.identifier + ' must have at least ' + this.minLength + ' ' + characterString);
        }
    }

        this.value = value;
    }

    public getValue(): string
    {
        return this.value;
    }

    public isEmpty(): boolean
    {
        return this.value.length === 0;
    }
}

class String255 extends EnforcedString
{
    constructor(value: string, identifier: string)
    {        
        super(0, 255, identifier);
        this.setValue(value);
    }
}

class String255Required extends EnforcedString
{   
    constructor(value: string, identifier: string)
    {        
        super(1, 255, identifier);
        this.setValue(value);
    }
}

由于Typescript的结构子类型系统,这意味着&#34; firstName&#34;在下面的构造函数中,即使我们将String255类分配给String255Required属性,也不会将其报告为错误。

class User 
{
    private id: UserId;
    private username: Username;
    private firstName: String255Required;
    private lastName: String255Required;

    constructor(
        id: UserId,
        username: Username,
        firstName: String255,
        lastName: String255Required
    ) {
        this.id = id;
        this.username = username;
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

所以问题是,处理结构子类型的最佳实践是什么。我可以在&#34;修复&#34;的类中引入无用的属性。问题,例如

class String255Required extends EnforcedString
{   
    private nope: boolean;      

    constructor(value: string, identifier: string)
    {        
        super(1, 255, identifier);
        this.setValue(value);
    }
}

编译器现在报告我期望的错误,因为String255Required与String255具有不同的属性,但这显然是不可取的。人们在做什么来避免这些问题?请注意,我尝试使用类来创建基于类型的业务规则。

1 个答案:

答案 0 :(得分:0)

我认为你的目标无论如何都无法实现。看下面:

+-----+-------------------+---+---------------------------------------------+
|index|time               |val|w                                            |
+-----+-------------------+---+---------------------------------------------+
|1    |2017-05-15 23:12:26|2.5|[2017-05-14 23:12:26.0,2017-05-19 23:12:26.0]|
+-----+-------------------+---+---------------------------------------------

此代码有效,因为谁扩展谁并不重要。重要的是类的参数/实例具有的属性。

仅当参数没有所需的属性时才会抛出错误。

有关详细信息,请参阅http://www.typescriptlang.org/docs/handbook/type-compatibility.html