Reputation: 21
I have a function need to define, such a function's usage can be simplify as below:
test({ flag: 1, payload: 123 }) // is ok
test({ flag: 1 }) // not ok
test({ flag: 2, payload: 123 }) // is ok
test({ flag: 2 }) // is ok
flag
is number 1
, payload must be appearflag
is not number 1
, payload is not requiredI was thinking of using function overloading to write such definiton. but turns out all definitions of function overloading is 'Or' relationship, and i can not define a type that exclude 1
from number
interface TestFunc {
(data: { flag: 1, payload: number }): void
// can I exclude 1 from number ?
(data: { flag: number, payload?: number }): void
}
const test: TestFunc = (data) => {
// ...
}
test({ flag: 1 }) // it should report type error
Upvotes: 0
Views: 78
Reputation: 33061
You can achieve smth similar to negation
:
type NotOne<T extends number> = T extends 1 ? never : T;
type WithOne = {
flag: 1,
payload: number
}
type WithoutOne<T extends number> = {
flag: NotOne<T>,
payload?: number
}
type Data<T extends number> = WithOne | WithoutOne<T>
interface TestFunc {
(data: WithOne): void
<T extends number>(data: WithoutOne<T>): void
}
const test: TestFunc = <T extends number>(data: Data<T>) => {
}
test({ flag: 1, payload: 123 }) // is ok
test({ flag: 1 }) // not ok
test({ flag: 2, payload: 123 }) // is ok
test({ flag: 2 }) // is ok
I have created NotOne
utility type for negation purpose. As you see, nothing complicated, it just returns never
if value is 1
.
Then, you need to make illegal state unrepresentable with union help Data<T>
Then, you need just use this union of two valid states to overloaded function.
Very similar example you can find in my blog
Upvotes: 0
Reputation: 7428
You can use extends
to detect if your flag
property equals to 1
- and correspondingly build the part with payload
:
interface Payload {
payload: number;
}
function test<T extends number>(data: { flag: T } & (T extends 1 ? Payload : Partial<Payload>)): void {
}
test({ flag: 1, payload: 123 }) // is ok
test({ flag: 1 }) // not ok
test({ flag: 2, payload: 123 }) // is ok
test({ flag: 2 }) // is ok
You can play with this example at the playground.
Upvotes: 2