Published on

Prefer precise string types

Authors

String type is big and giving variable a string type will give you a lot of possibilities input values. But with the great power comes great responsibility. Suppose you're building a book collection and want to define a type for a book. Here's an attempt to define a book type:


_6
interface Book {
_6
title: string;
_6
writer: string;
_6
publishedDate: string; // YYYY-MM-DD
_6
bookType: string; // hardcover, paperback, ebook
_6
}

That interface seems right but actually not. Here's what can go wrong:


_6
const book: Book = {
_6
title: 'Chemistry 12',
_6
writer: 'Marthen Kanginan',
_6
publishedDate: 'May 4th, 1945', // ooops, wrong format
_6
bookType: 'Hardcover' // ooops again, wrong type
_6
};

The publishedDate and bookType can be narrowed down to a more precise type. For publishedDate field it's better to use a Date object and avoid formatting issue. Then, for the bookType field, you can define a union type with just expected values. Here's the same interface with more precise types:


_8
type BookType = 'hardcover' | 'paperback' | 'ebook';
_8
_8
interface Book {
_8
title: string;
_8
writer: string;
_8
publishedDate: Date;
_8
bookType: BookType;
_8
}

With these changes Typescript is able to do a more thorough validation of the data.


_7
const book: Book = {
_7
title: 'Chemistry 12',
_7
writer: 'Marthen Kanginan',
_7
publishedDate: new Date('1945-05-04'),
_7
bookType: 'Hardcover'
_7
// type Hardcover is not assignable to type BookType
_7
};

Another example misuse of string is in function parameters. Let's say you want to create simple find by bookType function. Instead using string type, you can use a union type with just expected values.

If create function with parameters that expected to be properties on an object we can use keyOf T to narrow down the type of the parameter. For example pluck function with generic.


_3
function pluck<T, K extends keyof T>(records: T[], key: K): T[K][] {
_3
return record.map(r => r[key]);
_3
}

Wrap up

  • Avoid "stringly typed" code. Prefer more precise types where not every value is possible.
  • Use union types to define more precise types.
  • Prefer keyOf T to string for function parameters that are expected to be properties of an object.

Reference: