Urco Urco - 3 months ago 11
TypeScript Question

Typescript enforce partial interface

I have an application where I receive data in JSON format. A simplified example:

data {
prop1: "abc",
prop2: 123,
COL_A12: "mydata",
COL_A13: "myotherdata",
}


Where I know upfront that the data will have several prop1 and prop2 property names, but COL_A12 and COL_A13 are generated, so they could've followed other naming (i.e COL_A67).

I enforced an interface like

interface IData {
prop1: string;
prop2: number;
}


But I cannot specify the other property's name in the interface because I don't know the exact names, although they do follow a pattern.

Is there any way to provide a regular expression for the property name's in Typescript?

Answer

You have no way of setting a pattern for property names.
What you can do is:

interface IData {
    prop1: string;
    prop2: number;
    [name: string]: string | number;
}

So this is valid:

let data = {
    prop1: "abc",
    prop2:  123,
    COL_A12: "mydata",
    COL_A13: "myotherdata",
} as IData;

console.log(data.prop1); // ok
console.log(data.COL_A12); // error
console.log(data["COL_A12"]); // ok

The problem is that the indexable properties are of type string | number (because it can't be just string as the object has the prop2 which is a number), so:

let a = data["COL_A12"]; // typeof a is 'string | number'
let b = data["COL_A12"] as string; // typeof a is 'string'

Edit

As you receive the data, you have no way of controlling what's in it (if I understand correctly) so this interface is just to make sense of what data you get and its structure.

If you want to then control how this data is accessed in your application then you can create a class which takes this data and exposes specific getters, for example:

class Data {
    private raw: IData;

    constructor(data: IData) {
        this.raw = data;
    }

    public get prop1(): string {
        return this.raw.prop1;
    }

    public get prop2(): number {
        return this.raw.prop2;
    }

    public col(num: number): string {
        return this.raw[`COL_A${ num }`] as string;
    }
}