I would like to have a function whose input object keys are statically typed depending on the given value of some key. Here is a TypeScript playground with a failing test:
Playground Link
<code>export type Input<$Method extends URL | 'memory'> = {
method: $Method
} & ($Method extends URL ? { headers?: HeadersInit } : {})
declare const foo: <$Input extends Input<URL | 'memory'>>(input:$Input) => $Input
foo({ method: new URL('https://abc'), headers: {} }) // OK
foo({ method: new URL('https://abc') }) // OK
foo({ method: 'memory' }) // OK
// @ts-expect-error headers should be disallowed
foo({ method: 'memory', headers:{} })
// ^^^^^^^^^^ -- should error
</code>
<code>export type Input<$Method extends URL | 'memory'> = {
method: $Method
} & ($Method extends URL ? { headers?: HeadersInit } : {})
declare const foo: <$Input extends Input<URL | 'memory'>>(input:$Input) => $Input
foo({ method: new URL('https://abc'), headers: {} }) // OK
foo({ method: new URL('https://abc') }) // OK
foo({ method: 'memory' }) // OK
// @ts-expect-error headers should be disallowed
foo({ method: 'memory', headers:{} })
// ^^^^^^^^^^ -- should error
</code>
export type Input<$Method extends URL | 'memory'> = {
method: $Method
} & ($Method extends URL ? { headers?: HeadersInit } : {})
declare const foo: <$Input extends Input<URL | 'memory'>>(input:$Input) => $Input
foo({ method: new URL('https://abc'), headers: {} }) // OK
foo({ method: new URL('https://abc') }) // OK
foo({ method: 'memory' }) // OK
// @ts-expect-error headers should be disallowed
foo({ method: 'memory', headers:{} })
// ^^^^^^^^^^ -- should error
In the above, notice that headers
should only be allowed when method
is URL
type. But I have not solved how to achieve this. How can it be done?
Also notice that the inferred type is available in the output position (return).
— edit
One solution I found is using an Exact type helper, but is there a simpler way?
link
2