1

I’m studying TypeScript and came across this pattern:

type Animal = { [key: string]: number };
 
let Tiger: Animal = { legs: 4, age: 5, tail: 1, eyes :2 };

From what I understand, this allows adding unlimited properties, as long as the key is a string and the value is a number.

My question is:

Is this approach considered idiomatic in TypeScript?

Would there be a better way to type known + unknown properties with more structure?

4
  • You can have known + unknown properties in the same type as below : Here we’re saying that SquareConfig can have any number of properties, and as long as they aren’t color or width, their types don’t matter. ----> interface SquareConfig { color?: string; width?: number; [propName: string]: unknown; } -----> This has been detailed here typescriptlang.org/docs/handbook/2/… Commented Apr 19 at 5:24
  • You can bring in more structure to the unknown properties by typing the index signature with a union type as this ----> interface NumberOrStringDictionary { [index: string]: number | string; length: number; // ok, length is a number name: string; // ok, name is a string } -----> This has been detailed here typescriptlang.org/docs/handbook/2/… Commented Apr 19 at 5:29
  • You can also bring in more structure to the unknown part by typing it with a mapped type as this ---> type T0 = { a : number, b: string } type T1 = { [Property in keyof T0]: T0[Property] }; let someObject: T1 = { a: 4, b: "5" }; Commented Apr 19 at 5:30
  • The mapped types has been explained here typescriptlang.org/docs/handbook/2/mapped-types.html Commented Apr 19 at 5:31

1 Answer 1

2

There's 2 types of object structures in general - dictionaries (maps) (properties with the same type) and objects (properties with different types). (Though we could have a map with different value types). Semantically I'd say you have an object, not a map. A map would be for example number of legs from different animals.

I would not recommended to use such typing for an object. Loose typing like that have drawbacks like:

  1. You could make a type like lefs instead of legs
  2. You can't add additional props of different type like name: string

I would use an interface which you can extends with additional properties for different animal types:

interface Animal { 
  legs: number; 
  age: number, 
  tail: number, 
  eyes : number
};

interface Tiger extends Animal{
  color: 'stripes' | 'black'
}

let Tiger: Tiger = { legs: 4, age: 5, tail: 1, eyes :2 , color: 'stripes'};

If your structure is rather a map you could improve by typing the keys thus prohibiting typos and non-existing keys:

type Animal = Partial<Record<'legs'|'eyes'|'tail'|'age', number>>;
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you very much for your response. I am just learning the basics of TS right now, and you have provided a lot of information in your response.
I don't really think type Animal = Record<'legs'|'eyes'|'tail'|'age', number>; makes a lot of sense here. Occasionally you do work with dictionary-like items where the keys being a union fits but the Animal example doesn't quite fit. I'd instead elect to do a Partial<Animal> for it, as it more accurately describes "an animal but each of its properties might be missing", using Record doesn't convey the same information.
@VLAZ you are right
@AlexanderNenashev thanks a lot for sharing how stackoverflow works, this my first question here.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.