I have a type with an id
field (string) and an oldId
field (number).
But I don't want to have it in the same time
ex.
{ id: "1234", name: "foo" }
{ oldId: 1234, name: "bar" }
I tried this :
export type WithId<T> = T & ({ id: string } | { oldId: number })
export type Product = WithId<{
name: string
}>
const product1: Product = {
oldId: 12345,
name: "foo"
}
const product2: Product = {
id: "12345",
name: "bar"
}
This is working. But when it's a parameter, it's not working :
import { Product } from 'product'
export const someTest = (product: Product) => {
return product.id
}
I'm getting :
Property 'id' does not exist on type 'Product'.
CodePudding user response:
You will need to combine a never with a union similar to the example below.
The first part of the type { name: string }
is the "common" definition. This could be one of more properties.
Then this is followed by a union of "an id of type string but never an oldId" OR "an oldId of type number, but never an id".
Note that the never's need a ?
in this case
It's a very useful little pattern.
const product1 = { id: '1234', name: 'foo' };
const product2 = { oldId: 1234, name: 'bar' };
const product9 = { id: '1234', oldId: 1234, name: 'bar' };
type Product = { name: string } & (
| {
id: string;
oldId?: never;
}
| {
id?: never;
oldId: number;
}
);
const printProduct = (product: Product) => {
console.log(product.name);
}
printProduct(product1);
printProduct(product2);
printProduct(product9); // <-- won't be accepted, because product9 has both an id and an oldId