This one is a bit tricky to describe in words, so I will just start with the code. Let's say I have to deal with strings that have the following format:
type ColumnName<
Prefix extends string,
Period extends 'month' | 'week'
> = `${Prefix}.${Period}`;`
For example, ColumnName<'dimension_date', 'month'>
would be 'dimension_date.month'
. Now let
type Month<Prefix extends string> = ColumnName<Prefix, 'month'>;
type Week<Prefix extends string> = ColumnName<Prefix, 'week'>;
Next, I have a function that takes either a Month
or a Week
, and a Prefix
:
const get = <Prefix extends string>(
column: Month<Prefix> | Week<Prefix>,
prefix: Prefix
) => {
const monthColumn: ColumnName<Prefix, 'month'> = `${prefix}.month`;
if (column === monthColumn) {
console.log(column); // column has type `${Prefix}.month`, as expected
}
};
This works as expected. However, I actually need column
to be an object property:
type MonthObject<Prefix extends string> = { [K in Month<Prefix>]: number };
type WeekObject<Prefix extends string> = { [K in Week<Prefix>]: number };
const getObj = <Prefix extends string>(
object: MonthObject<Prefix> | WeekObject<Prefix>,
prefix: Prefix
) => {
const monthColumn: ColumnName<Prefix, 'month'> = `${prefix}.month`;
if (monthColumn in object) {
console.log(object); // object has type MonthObject<Prefix> | WeekObject<Prefix>, while it expect it to only have type MonthObject<Prefix>.
}
}
Is there a way to make typescript understand that inside of the if statement the type can only be MonthObject<Prefix>
?
CodePudding user response:
You can use a function to assert the type.
const isMonth =
<Prefix extends string>(obj: MonthObject<Prefix> | WeekObject<Prefix>, prefix: Prefix)
: obj is MonthObject<Prefix> => {
const monthColumn: ColumnName<Prefix, 'month'> = `${prefix}.month`;
return monthColumn in obj
}
And use this function as the condition.
const getObj = <Prefix extends string>(
object: MonthObject<Prefix> | WeekObject<Prefix>,
prefix: Prefix
) => {
if (isMonth(object, prefix)) {
console.log(object);
// ^? (parameter) object: MonthObject<Prefix>
}
}