Skip to content

Commit ebcafa1

Browse files
committed
Refactor ecmascript.ts (port of 1980 & 1976)
Port of tc39/proposal-temporal#1976 and tc39/proposal-temporal#1980.
1 parent 8ebbd47 commit ebcafa1

File tree

1 file changed

+30
-30
lines changed

1 file changed

+30
-30
lines changed

lib/ecmascript.ts

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ function abs(x: JSBI): JSBI {
170170
return x;
171171
}
172172

173-
const BUILTIN_CASTS = new Map<PrimitivePropertyNames, (v: unknown) => string | number>([
173+
type BuiltinCastFunction = (v: unknown) => string | number;
174+
const BUILTIN_CASTS = new Map<PrimitivePropertyNames, BuiltinCastFunction>([
174175
['year', ToIntegerThrowOnInfinity],
175176
['month', ToPositiveInteger],
176177
['monthCode', ToString],
@@ -306,7 +307,7 @@ function ParseTemporalTimeZone(stringIdent: string) {
306307
let { ianaName, offset, z } = ParseTemporalTimeZoneString(stringIdent);
307308
if (ianaName) return ianaName;
308309
if (z) return 'UTC';
309-
return offset;
310+
return offset; // if !ianaName && !z then offset must be present
310311
}
311312

312313
function FormatCalendarAnnotation(id: string, showCalendar: Temporal.ShowCalendarOption['calendarName']) {
@@ -1068,35 +1069,38 @@ export function LargerOfTwoTemporalUnits<T1 extends Temporal.DateTimeUnit, T2 ex
10681069
return unit1;
10691070
}
10701071

1071-
export function ToPartialRecord<B extends AnyTemporalLikeType>(
1072-
bag: B,
1073-
fields: readonly (keyof B)[],
1074-
callerCast?: (value: unknown) => unknown
1075-
) {
1076-
if (!IsObject(bag)) return false;
1077-
let any: B;
1072+
export function ToPartialRecord<B extends AnyTemporalLikeType>(bagParam: B, fieldsParam: ReadonlyArray<keyof B>) {
1073+
// External callers are limited to specific types, but this function's
1074+
// implementation uses generic property types. The casts below (and at the
1075+
// end) convert to/from generic records.
1076+
const bag = bagParam as Record<PrimitivePropertyNames & keyof B, string | number | undefined>;
1077+
const fields = fieldsParam as ReadonlyArray<keyof B & PrimitivePropertyNames>;
1078+
let any = false;
1079+
let result = {} as typeof bag;
10781080
for (const property of fields) {
10791081
const value = bag[property];
10801082
if (value !== undefined) {
1081-
any = any || ({} as B);
1082-
if (callerCast === undefined && BUILTIN_CASTS.has(property as PrimitivePropertyNames)) {
1083-
any[property] = BUILTIN_CASTS.get(property as PrimitivePropertyNames)(value) as unknown as B[keyof B];
1084-
} else if (callerCast !== undefined) {
1085-
any[property] = callerCast(value) as unknown as B[keyof B];
1083+
any = true;
1084+
if (BUILTIN_CASTS.has(property)) {
1085+
result[property] = (BUILTIN_CASTS.get(property) as BuiltinCastFunction)(value);
10861086
} else {
1087-
any[property] = value;
1087+
result[property] = value;
10881088
}
10891089
}
10901090
}
1091-
return any ? any : false;
1091+
return any ? (result as B) : false;
10921092
}
10931093

10941094
export function PrepareTemporalFields<B extends AnyTemporalLikeType>(
1095-
bag: B,
1096-
fields: ReadonlyArray<FieldRecord<B>>
1097-
): Required<B> | undefined {
1098-
if (!IsObject(bag)) return undefined;
1099-
const result = {} as B;
1095+
bagParam: B,
1096+
fieldsParam: ReadonlyArray<FieldRecord<B>>
1097+
): Required<B> {
1098+
// External callers are limited to specific types, but this function's
1099+
// implementation uses generic property types. The casts below (and at the
1100+
// end) convert to/from generic records.
1101+
const bag = bagParam as Record<PrimitivePropertyNames & keyof B, string | number | undefined>;
1102+
const fields = fieldsParam as ReadonlyArray<FieldRecord<typeof bag>>;
1103+
const result = {} as typeof bag;
11001104
let any = false;
11011105
for (const fieldRecord of fields) {
11021106
const [property, defaultValue] = fieldRecord;
@@ -1105,15 +1109,11 @@ export function PrepareTemporalFields<B extends AnyTemporalLikeType>(
11051109
if (fieldRecord.length === 1) {
11061110
throw new TypeError(`required property '${property}' missing or undefined`);
11071111
}
1108-
// TODO: two TS issues here:
1109-
// 1. `undefined` was stripped from the type of `defaultValue`. Will it
1110-
// come back when strictNullChecks is enabled?
1111-
// 2. Can types be improved to remove the need for the type assertion?
1112-
value = defaultValue as unknown as typeof bag[typeof property];
1112+
value = defaultValue;
11131113
} else {
11141114
any = true;
11151115
if (BUILTIN_CASTS.has(property as PrimitivePropertyNames)) {
1116-
value = BUILTIN_CASTS.get(property as PrimitivePropertyNames)(value) as unknown as typeof bag[keyof B];
1116+
value = (BUILTIN_CASTS.get(property) as BuiltinCastFunction)(value);
11171117
}
11181118
}
11191119
result[property] = value;
@@ -1122,12 +1122,12 @@ export function PrepareTemporalFields<B extends AnyTemporalLikeType>(
11221122
throw new TypeError('no supported properties found');
11231123
}
11241124
if (
1125-
((result as Temporal.PlainDateLike)['era'] === undefined) !==
1126-
((result as Temporal.PlainDateLike)['eraYear'] === undefined)
1125+
((result as { era: unknown })['era'] === undefined) !==
1126+
((result as { eraYear: unknown })['eraYear'] === undefined)
11271127
) {
11281128
throw new RangeError("properties 'era' and 'eraYear' must be provided together");
11291129
}
1130-
return result as Required<B>;
1130+
return result as unknown as Required<B>;
11311131
}
11321132

11331133
// field access in the following operations is intentionally alphabetical

0 commit comments

Comments
 (0)