0
votes

i can't compile this kind of thing:

type F<A> = (a:A)=>A;

class CLAZZ<S extends { [k: string]: any }, K extends keyof S = keyof S>{
  constructor(a:S){
    this._o=a;
  }
  _o:S;
  set(k:K, f:F<S[K]>){
     f(this._o[k]);
  }
}

type O = {
  pippo: number,
  pluto: string | null,
  paperino: {[k:string]:boolean}
}

let o = new CLAZZ<O>({"paperino":{}, pluto:null, pippo:1});

o.set("paperino", (paperino)=>({...paperino, "ciccio":true}))

playground

the last line give this error:

Spread types may only be created from object types.

this because the paperino argument is inferred as

(parameter) paperino: string | number | { [k: string]: boolean; } | null

and not just as

{ [k: string]: boolean; }

as i'm expecting...

also forcing the parameter type give me an error

o.set("paperino", (paperino: {[k:string]:boolean})=>({...paperino,"ciccio":true}))

Argument of type '(paperino: { [k: string]: boolean; }) => { ciccio: true; }' is not assignable to parameter of type 'F<string | number | { [k: string]: boolean; } | null>'. Types of parameters 'paperino' and 'a' are incompatible. Type 'string | number | { [k: string]: boolean; } | null' is not assignable to type '{ [k: string]: boolean; }'. Type 'null' is not assignable to type '{ [k: string]: boolean; }'.

any solution other than... "any"?

1
Because TS figures out types when you create an object, not when you call set, if you want types to be narrowed when you call a function, you can make it generic as well, something like set<K1 extends K>(k:K1, f:F<S[K1]>) should do. (CLAZZ<O> that just looks a bit misspelled :D )Nadia Chibrikova

1 Answers

0
votes

just move the key generic to the set method: playground