I have tried to create a type that changes depending on which enum's value is being used:
enum StatusEnum {
UPDATE = 'update',
CREATE = 'create'
}
type LogKeyType<K extends StatusEnum> =
K extends StatusEnum.UPDATE ? Record<string, any> : undefined
type Props = {
status: StatusEnum
log: LogKeyType<status> // <-- here is the key that should change type depending on status
// other keys...
}
For this line : log: LogKeyType<status>
I get an error saying that status refers as a value but is being used as a type and I did not manage to get pass this error.
I've then tried to to use generic type too :
enum StatusEnum {
UPDATE = 'update',
CREATE = 'create'
}
type LogKeyType<K extends StatusEnum> =
K extends StatusEnum.UPDATE ? Record<string, any> : undefined
type Props<K extends StatusEnum> = {
status: K
log: LogKeyType<K>
// other keys...
}
but typescript can't tell what's the type of log
.
This is to be used in this use case :
if (props.status === StatusEnum.UPDATE) {
// do something with props.log that won't be undefined
}
I could also check directly if log is undefined or not but it wouldn't be as fancy.
EDIT:
Here is the error I'm talking about in my comment from Baka's answer : playground link
CodePudding user response:
What you're looking for is discriminated union
Here's an example of how you can use it with your enum:
import React from 'react';
enum StatusEnum {
UPDATE = 'update',
CREATE = 'create'
}
interface BaseProps {
status: StatusEnum;
// other keys...
someArbitraryKey: string;
}
interface Update extends BaseProps {
status: StatusEnum.UPDATE;
log: Record<string, any>;
}
interface Create extends BaseProps {
status: StatusEnum.CREATE;
}
type Props = Update | Create;
export const Component: React.FC<Props> = props => {
if (props.status === StatusEnum.UPDATE) {
return <div>{props.log}</div>; // no type error
}
if (props.someArbitraryKey.length) { // someArbitraryKey is always available
return <div>{props.log}</div>; // error, undefined log
}
return <div />;
}