Typescript: Generic constrained to mapped type should work with spread types

Created on 28 Jun 2017  路  3Comments  路  Source: microsoft/TypeScript

I think I'm getting a false error related to object spread types. Example code below. The shape of Record is limited to simple vanilla objects with no nested/methods/etc.

TypeScript Version: 2.3.2

Code

namespace Foo {

    type Value = string | number | boolean | null;

    type Record<K extends string> = { readonly [P in K]: Value; };

    type RecordTable<T extends Record<keyof T>> = { readonly [id: string]: T; }

    function update<T extends Record<keyof T>>(table: RecordTable<T>, id: string, values: Partial<T>): RecordTable<T> {

      let record = { ...table[id], ...values };  // This line fails at `...table[id]`` with "error TS2698: Spread types may only be created from object types."

      return { ...table, [id]: record };
    }

    // Usage
    interface IFoo extends Record<keyof IFoo> {
      foo: number;
      bar: string;
      //baz: number[];  // fails like it should when uncommented
    }

    let table: RecordTable<IFoo>;

    update(table, 'someId', { foo: 12 });  // okay
    update(table, 'someId', { baz: 4 });   // fails like it should, "baz" invalid property
}

Expected behavior:
Should compile cleanly.

Actual behavior:
Does not compile.

Bug Duplicate

Most helpful comment

Another, simpler example:

function clone1<S>(thing: S): S {
  return { ...thing };  // not okay, but explainable
}

function clone2<S extends object>(thing: S): S {
  return { ...thing };  // not okay, but it probably should be
}

All 3 comments

Simplifying a bit

type Mapped = {[k in keyof Window]: string };
function fn<T extends Mapped>(x: T) {
    // should be OK
    var y = { ...x };
}

Another, simpler example:

function clone1<S>(thing: S): S {
  return { ...thing };  // not okay, but explainable
}

function clone2<S extends object>(thing: S): S {
  return { ...thing };  // not okay, but it probably should be
}

This should work if typescript allowed generics to be spread, but it doesn't. The main issue that tracks adding spread types that allow generics is #10727

Specifically, the return types of clone1 and clone2 are wrong. They should return spread(S) not S. Same for fn: its type would be spread(T) if it were to return y.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DanielRosenwasser picture DanielRosenwasser  路  3Comments

uber5001 picture uber5001  路  3Comments

Antony-Jones picture Antony-Jones  路  3Comments

siddjain picture siddjain  路  3Comments

jbondc picture jbondc  路  3Comments