Description
TypeScript Version: 3.5.1, 3.7.2
Search Terms:
Force TS to alias type, optional property, type expand
Code
type Identity<T> = T;
type PleaseDoNotExpand<T> =
| T
| { x : T }
;
type MappedType<ObjT> =
Identity<
& {
readonly [k in Exclude<keyof ObjT, "x">]: (
PleaseDoNotExpand<ObjT[k]>
)
}
& {
readonly [k in Extract<keyof ObjT, "x">]?: (
PleaseDoNotExpand<ObjT[k]>
)
}
>
;
declare function mappedType<ObjT>(obj: ObjT): MappedType<ObjT>;
/*
Expected:
const x: {
readonly y: PleaseDoNotExpand<string>;
readonly z: PleaseDoNotExpand<boolean>;
} & {
readonly x?: PleaseDoNotExpand<number>|undefined;
}
*/
/*
Actual:
const x: {
readonly y: PleaseDoNotExpand<string>;
readonly z: PleaseDoNotExpand<boolean>;
} & {
readonly x?: number | {
x: number;
} | undefined;
}
*/
const x = mappedType({
x: 1,
y: "hi",
z: true,
});
Expected behavior:
Expected x
to resolve to,
const x: {
readonly y: PleaseDoNotExpand<string>;
readonly z: PleaseDoNotExpand<boolean>;
} & {
readonly x?: PleaseDoNotExpand<number>|undefined;
}
Actual behavior:
Actually resolves to,
const x: {
readonly y: PleaseDoNotExpand<string>;
readonly z: PleaseDoNotExpand<boolean>;
} & {
readonly x?: number | {
x: number;
} | undefined;
}
This behaviour is caused by the ?
optional property modifier. It seems to do something that messes up emit, and makes it inconsistent with required properties.
Since required properties do not expand the PleaseDoNotExpand<>
type,
optional properties should also not expand the PleaseDoNotExpand<>
type.
I believe this is a bug in emit.
Playground Link:
Related Issues:
Kind of related to this,
#34556
That issue wants a way to future-proof ways of forcing TS to not alias a type.
The Identity<>
trick works nicely at the moment.
Also related to this,
#34777
That issue wants a way to force TS to always alias a type.
There is a workaround using interface
when the properties are always known and you do not have union types.
It does not apply in this case, because I have union types.
This mini-rant probably belongs in a different issue but...
I would like a way to have TS never expand a type alias for hover tooltip and emit.
Not by default, anyway.
My actual PleaseDoNotExpand<>
type is easily 100+ lines long. It makes everything unreadable, when TS fully expands it.
I can read PleaseDoNotExpand<Date>
better than I can read the following,
readonly createdAt?: Date | tsql.IExpr<{
mapper: Mapper<unknown, Date>;
usedRef: tsql.IUsedRef<{}>;
}> | (tsql.IQueryBase<{
fromClause: tsql.IFromClause<tsql.FromClauseData>;
selectClause: [tsql.IColumn<{
tableAlias: string;
columnAlias: string;
mapper: Mapper<unknown, Date>;
}> | tsql.IExprSelectItem<{
mapper: Mapper<unknown, Date>;
tableAlias: string;
alias: string;
usedRef: tsql.IUsedRef<never>;
}>];
limitClause: tsql.LimitClause | undefined;
compoundQueryClause: readonly tsql.CompoundQuery[] | undefined;
compoundQueryLimitClause: tsql.LimitClause | undefined;
mapDelegate: tsql.MapDelegate<never, never, unknown> | undefined;
}> & tsql.IQueryBase<{
fromClause: tsql.IFromClause<{
outerQueryJoins: readonly tsql.IJoin<tsql.JoinData>[] | undefined;
currentJoins: undefined;
}>;
selectClause: readonly (tsql.ColumnMap | tsql.IColumn<tsql.ColumnData> | tsql.IExprSelectItem<tsql.ExprSelectItemData> | tsql.ColumnRef)[] | undefined;
limitClause: tsql.LimitClause | undefined;
compoundQueryClause: undefined;
compoundQueryLimitClause: tsql.LimitClause | undefined;
mapDelegate: tsql.MapDelegate<never, never, unknown> | undefined;
}> & tsql.IQueryBase<{
fromClause: tsql.IFromClause<{
outerQueryJoins ...