ken
ken

Reputation: 8993

how can you express "keyof T" to be a subset of String?

The Firebase typings have an interface IQuery which has the equalTo() method typed as:

public equalTo(value: number | string | boolean | null, name?: string): IQuery;

I have a mocking library which is trying to mimic the API surface of what Firebase is exposing but in the case of the name parameter the general typing of "string" can be made more specific:

 public equalTo(value: number | string | boolean | null, key?: keyof T): IQuery<T>

By stating keyof T we get some very useful static checking that I'd hate to lose out on and in fact up to TypeScript 2.8.3 I seemed to be able to do this but when moving to 2.9.x+ of Typescript I now get this error:

Type 'string' is not assignable to type 'keyof T'.

For a bit more context, the class definition in my mocking library is:

 export default class Query<T = any> implements IQuery<T> { ... }

Where the <T> generic type is an indicator of type of the data structure that the query will return.

Further it is worth noting that T, will always be shaped as a dictionary/hash with string keys and therefore keyof T will subset of string values but in my typing I'm not making this clear so I get where Typescript is taking issue ... I just don't know how to express that keyof T must be a string.

Upvotes: 8

Views: 6689

Answers (2)

madox2
madox2

Reputation: 51841

You can also require keys in your type to be string-only:

key?: keyof T & string

Upvotes: 4

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249536

This is related to a change in the way keyof works in 2.9, until 2.9 keyof only returned string keys, from 2.9 onward it will return number and symbol keys. This is the reference for this

To only accept string keys you can use Extract<keyof T, string> as the type for the key parameter, or if you want to revert to the old behavior you can use the --keyofStringsOnly compiler flag

public equalTo(value: number | string | boolean | null, key?: Extract<keyof T, string>): IQuery<T>

Upvotes: 12

Related Questions