Skip to content

Feature request: Allow index types to be subtypes of string #13285

Closed
@danvk

Description

@danvk

See this example from a medium post on mapped types.

I have a function updateIds which runs some subset of properties on an object through a mapping:

> updateIds({id: 'old', other: 3},
            ['id'],
            {'old': 'new'})
{id: 'new', other: 3}

> updateIds({from: 'A', to: 'B', time: 180},
            ['from', 'to'],
            {'A': 'A1', 'B': 'B1'})
{from: 'A1', to: 'B1', time: 180}

This function is simple to implement but not entirely straightforward to type. Here's a version using keyof:

function updateIds<T>(
  obj: T,
  idFields: (keyof T)[],
  idMapping: {[oldId: string]: string}
): T {
  for (const idField of idFields) {
    const newId = idMapping[obj[idField] as any];  // <--
    if (newId) {
      obj[idField] = newId as any;  // <--
    }
  }
  return obj;
}

The problem here is that obj[idField] has a type of T[keyof T] whereas it really needs to have a type of string. I'd like the type system to require that T[k] = string for all the fields passed in the array.

I don't believe there's any way to do this directly (please tell me if I'm wrong!)

One thought was to use a second type parameter for the property list:

function updateIds<K extends string, T extends {[k: K]: string}>(
  obj: T,
  idFields: K[],
  idMapping: {[oldId: string]: string}
): T {}

But this gives the error An index signature parameter type must be 'string' or 'number'. If the index signature parameter could instead be a subtype of string (e.g. "from" | "to") then I think this would work.

TypeScript Version: 2.1.4

Code

updateIds({id: /not a string/}, 'id', {'old': 'new'})

Expected behavior:

I'd like this to be rejected since the id field doesn't have a string type.

Actual behavior:

I don't have a way to enforce this through the type system.

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions