interface DefaultProps3 {
instantPopoup?: boolean;
// ...
}
interface PropsWithCb3 extends DefaultProps3 {
path?: never;
cb(): void;
}
interface PropsWithPath3 extends DefaultProps3 {
cb?: never;
path: string;
}
const test3: PropsWithCb3 | PropsWithPath3 = { // ERROR
cb: () => {},
instantPopoup: true,
path: "df"
}
// =====================================
interface DefaultProps4 {
instantPopoup?: boolean;
// ...
}
interface PropsWithCb4 extends DefaultProps4 {
action: "cb";
cb(): void;
}
interface PropsWithPath4 extends DefaultProps4 {
action: "path";
path: string;
}
const test4: PropsWithCb4 | PropsWithPath4 = {
action: "cb",
cb: () => {},
instantPopoup: true,
path: "df", // ERROR - более явно указывает на ошибку
}
// utils.d.ts
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = (Without<T, U> & U) | (Without<U, T> & T);
// component.tsx
type DefaultProps = {
instantPopoup?: boolean;
// ...
}
type PropsWithCb = { cb(): void; }
type PropsWithPath = { path: string; }
type Props = DefaultProps & XOR<PropsWithCb, PropsWithPath>;
const fn = (props: Props): void => {}
const p1: Props = { instantPopoup: true, path: "/test" }; // good
const p2: Props = { instantPopoup: false, cb: () => {} }; // good
fn({ instantPopoup: false, path: "/test" }); // good
fn({ instantPopoup: false, cb: () => {} }); // good
const error1: Props = { instantPopoup: true, path: "/test", cb: () => {} }; // error
const error2: Props = { instantPopoup: true }; // error
fn({ instantPopoup: false, cb: () => {}, path: "" }); // error
fn({ instantPopoup: false }); // error
interface DefaultProps4 {
instantPopoup?: boolean;
// ...
}
interface PropsWithCb4 extends DefaultProps4 {
cb(): void;
}
interface PropsWithPath4 extends DefaultProps4 {
path: string;
}
type Magic = ((arg: PropsWithCb4) => 1) & ((arg: PropsWithPath4) => 2);
declare const magic: Magic;
// error
magic({
cb: () => {},
instantPopoup: true,
path: "df",
});
// 1, no error
magic({
cb: () => {},
instantPopoup: true,
})
// 2, no error
magic({
instantPopoup: true,
path: "df",
})
const trololo = {
cb: () => {},
instantPopoup: true,
path: "df",
}
magic(trololo); // 1, no error