1

I would like to define a type where all the attributes are read only and looks like key:string value:string, but the 'set' attribute is a function.

I have tried the following:

type Attributes = {
  readonly [key in Exclude<string, 'set'>]:string
} & { 
  readonly set: (attr:string, value:string) => void 
}

My problem is Exclude<string, 'set'> is "simplified" back into string. Could someone with more experience explain why TypeScript does this? Some suggestions how to achive a type where I know only few property keys (but there can be many more) could help me out.

Thank you for your time and answers!

Bálint Réthy
  • 411
  • 1
  • 6
  • 25
  • 1
    Negated types were experimented with in [microsoft/TypeScript#29317](https://github.com/microsoft/TypeScript/pull/29317) but never made it into the language. So there's no way to say `string & not 'set'`. The `Exclude` utility type doesn't do it, as it only removes things from unions, and `string` is not a union. since your main question seems to actually be about having a "default" or "rest" property, I've closed this as a duplicate where [this answer](https://stackoverflow.com/a/61434547/2887218) explains the options. If I translate that code here I get [this](https://tsplay.dev/w2K1rN). – jcalz Aug 27 '21 at 20:02

1 Answers1

1

Currently in typescript it is not possible to create a type like "any string except ...", Exclude<string, '...'> always results in string. This is just a limitation of typescript we have to deal with for now.

Anyway it seems like this type works

type Attributes = {
  readonly [key: string]: string
} & { 
  readonly set: (attr:string, value:string) => void 
}

You cannot assign an object without set property to it and this property must be a function that you specified there, so it seems like you can just use it

Alex Chashin
  • 3,129
  • 1
  • 13
  • 35
  • When I call the `set` function TS compiler gives error: `This expression is not callable. Not all constituents of type 'string | ((attr: string, value: string => void)' are callable. Type 'string' has no call signatures.` – Bálint Réthy Aug 27 '21 at 21:17
  • Oh yes, forgot about that. Then I believe it's not possible to do this in typescript, you have to add type assertions when you call your function – Alex Chashin Aug 28 '21 at 10:19