-1

I want to define a type which is like response headers, which is like:

type Headers = { [key: string]: string }

but if the key is set-cookie, its type should be string[].

I tried

type Headers = { 'set-cookie'?: string[] } & { [key: string]: string };

but for code:

const headers: H = {
  'set-cookie': ['cookie'],
  'aaa': '111'
}

it has compilation errors:

TS2322: Type '{ 'set-cookie': string[]; aaa: string; }' is not assignable to type 'Headers'.   
Type '{ 'set-cookie': string[]; aaa: string; }' is not assignable to type '{ [key: string]: string; }'.     
Property ''set-cookie'' is incompatible with index signature.       
Type 'string[]' is not assignable to type 'string'.

Is it possible to define such a typing?

Freewind
  • 193,756
  • 157
  • 432
  • 708
  • @jcalz Thanks but a little sad to know the answer :( – Freewind May 10 '20 at 01:41
  • Me too; my only suggestion is that everyone who feels like this should be possible should go to [microsoft/TypeScript#17867](https://github.com/microsoft/TypeScript/issues/17867) and give it a and possibly explain why it's important for their use case. If more people want a feature and can make a strong argument why having it improves the language then there's more of a chance of it being implemented. – jcalz May 10 '20 at 01:52

1 Answers1

0

Your Headers type should be an intersection of two types.

interface CookieHeader {'set-cookie'?: string[]; }

Defines the set-cookie key to a type string[], also optional (?), since your Headers object may not have this property.

The second definition is quite more complex

type CommonHeaders = { [key: string]: string } & { 'set-cookie'?: never };

This is literally defining an interface of string keys without a set-cookie key.
Take a look to the Typescript utility types.

Then, the Headers type definition is easy

type Headers = CookieHeader | CommonHeaders;

const headers1: Headers = {
    key1: `value1`,
    key2: `value2`,
    'set-cookie': [`prop1`, `prop2`]
}; // Good

const headers2: Headers = {
    key1: `value1`,
    key2: `value2`
}; // Still good

const headers3: Headers = {
    key1: `value1`,
    key2: `value2`,
    'set-cookie': `prop1`
}; // Type 'string' is not assignable to type 'string[]'.

Hope it helps.

VRoxa
  • 973
  • 6
  • 25
  • thanks, but I have a question about the `CommonHeaders`, seems we have to use `any` as the type of keys to make it work? So other keys can be non-strings, like `key1: 123` – Freewind May 10 '20 at 00:51
  • Seems like you misused `Exclude`, its definition is `type Exclude = T extends U ? never : T`, so your `Headers` is actually `CookieHeader & {[key: string]: any; }` – Freewind May 10 '20 at 00:56
  • You are right, let me change the answer, (: – VRoxa May 10 '20 at 01:03
  • Done. With the change, the `Headers` type must be the union of `CookieHeader` or `CommonHeaders`. If stays as the intersection, `set-cookies` would have to be `string[] & never` which is resolved as `never`. – VRoxa May 10 '20 at 01:09
  • Still doesn't work if you set `set-cookies` with any other keys. `headers1` and `headers3` has compilation errors in my side (typescript 3.8.3) – Freewind May 10 '20 at 01:15
  • Have you changed the `Headers` declaration from intersection to union? `type Headers = CookieHeader | CommonHeaders;` – VRoxa May 10 '20 at 01:17
  • Yes, please see – Freewind May 10 '20 at 01:23
  • I am trying to figure out what is wrong. It must be something related to the tsconfig, because it is working perfectly for me... – VRoxa May 10 '20 at 01:44