Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Typescript, why am I required to set the property of a class that is defined as read-only?

Tags:

typescript

I have the following class definition:

class Department
{
    name: string;
    id: string;

    get prefix(): string
    {
        return  !isNaN(parseFloat(this.id)) ? "n" : "i" ;
    }
}

Elsewhere in my code, I try to use it like this:

getDepartmentList(): Department[] {
    return [
        {
            "name": "Dept 1",
            "id": "1000"
        }
    ];
}

However, I get the following error:

Type '{ "name": string; "id": string; }' is not assignable to type 'Department'. Property 'prefix' is missing in type '{ "name": string; "id": string; }'.

I am sure the real problem is my lack of understanding of Typescript, but can someone explain why the compiler sees the getter function as a property and expects me to set a value on it?

like image 665
July.Tech Avatar asked Aug 03 '16 20:08

July.Tech


People also ask

How do you set a readonly property in TypeScript?

Creating Read-Only Properties in TypeScript To create a read-only property, we prefix the keyword readonly before the property name. In the example below the price property is marked as readonly . We can assign a value to the price property when we initialize the object. However, we cannot change its value afterward.

What is readonly property in TypeScript?

TypeScript includes the readonly keyword that makes a property as read-only in the class, type or interface. Prefix readonly is used to make a property as read-only. Read-only members can be accessed outside the class, but their value cannot be changed.

How do I get rid of readonly properties in TypeScript?

You can use mapping modifiers to change a readonly property to mutable in TypeScript, e.g. -readonly [Key in keyof Type]: Type[Key] . You can remove the readonly modifier by prefixing the readonly keyword with a minus - .

Can you restrict TypeScript object to contain only properties defined by its class?

Typescript can't restrict extra properties Unfortunately this isn't currently possible in Typescript, and somewhat contradicts the shape nature of TS type checking.


1 Answers

Your class Department is creating a type Department. You are defining that to contain name, id and prefix. The objects you return in getDepartmentList does not contain the prefix, so they are not structurally compatible with the type Department. Hence you get an error.

I guess that you assume that the prefix-property will be available on anything do declare to be of the type Department. This is not the case, there is no kind of dynamic class assignments like that in typescript. You have to make sure yourself that objects that you say is certain type, actually fulfill that type.

You could do it something like this:

class Department
{
    constructor(public name:string, public id:string){ }

    get prefix(): string
    {
        return  !isNaN(parseFloat(this.id)) ? "n" : "i" ;
    }
}

function getDepartmentList(): Department[]
{
    return [new Department("Dept 1", "1000")];
}

Here you are instantiating new objects from the Department class, hence those objects will all have the prefix property.

The use of the access modifier in the constructor signature is telling typescript to create a property of that parameter, instead of only being treated as an argument.

It's equivalent to:

class Department
{
    name: string;
    id:string;

    constructor(name:string, id:string){
        this.name = name;
        this.id = id;
    }

    get prefix(): string
    {
        return  !isNaN(parseFloat(this.id)) ? "n" : "i" ;
    }
}
like image 162
Alex Avatar answered Sep 27 '22 23:09

Alex