Rearrange Dictionary type parameters for improved Record type inference
This commit is contained in:
parent
8f2da8f8db
commit
178f528bf0
|
@ -122,8 +122,8 @@ export class Decoder<T = never> implements TypedDecoder<T> {
|
|||
return this.includeAnnotations ? new Annotated(v) : v;
|
||||
}
|
||||
|
||||
static dictionaryFromArray<T>(vs: Value<T>[]): Dictionary<Value<T>, T> {
|
||||
const d = new Dictionary<Value<T>, T>();
|
||||
static dictionaryFromArray<T>(vs: Value<T>[]): Dictionary<T> {
|
||||
const d = new Dictionary<T>();
|
||||
if (vs.length % 2) throw new DecodeError("Missing dictionary value");
|
||||
for (let i = 0; i < vs.length; i += 2) {
|
||||
d.set(vs[i], vs[i+1]);
|
||||
|
|
|
@ -75,14 +75,14 @@ export class KeyedDictionary<K extends Value<T>, V, T = DefaultPointer> extends
|
|||
}
|
||||
}
|
||||
|
||||
export class Dictionary<V, T = DefaultPointer> extends KeyedDictionary<Value<T>, V, T> {
|
||||
static isDictionary<V, T = DefaultPointer>(x: any): x is Dictionary<V, T> {
|
||||
export class Dictionary<T = DefaultPointer, V = Value<T>> extends KeyedDictionary<Value<T>, V, T> {
|
||||
static isDictionary<T = DefaultPointer, V = Value<T>>(x: any): x is Dictionary<T, V> {
|
||||
return x?.[DictionaryType] === 'Dictionary';
|
||||
}
|
||||
|
||||
static fromJS<V = DefaultPointer, T = DefaultPointer>(x: object): Dictionary<Value<V>, T> {
|
||||
if (Dictionary.isDictionary<Value<V>, T>(x)) return x as Dictionary<Value<V>, T>;
|
||||
const d = new Dictionary<Value<V>, T>();
|
||||
static fromJS<T = DefaultPointer, V = DefaultPointer>(x: object): Dictionary<T, Value<V>> {
|
||||
if (Dictionary.isDictionary<T, Value<V>>(x)) return x;
|
||||
const d = new Dictionary<T, Value<V>>();
|
||||
Object.entries(x).forEach(([key, value]) => d.set(key, fromJS(value)));
|
||||
return d;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ export interface FoldMethods<T, R> {
|
|||
record(r: Record<Value<T>, Tuple<Value<T>>, T>, k: Fold<T, R>): R;
|
||||
array(a: Array<Value<T>>, k: Fold<T, R>): R;
|
||||
set(s: Set<T>, k: Fold<T, R>): R;
|
||||
dictionary(d: Dictionary<Value<T>, T>, k: Fold<T, R>): R;
|
||||
dictionary(d: Dictionary<T>, k: Fold<T, R>): R;
|
||||
|
||||
annotated(a: Annotated<T>, k: Fold<T, R>): R;
|
||||
|
||||
|
@ -57,7 +57,7 @@ export abstract class ValueFold<T, R = T> implements FoldMethods<T, Value<R>> {
|
|||
set(s: Set<T>, k: Fold<T, Value<R>>): Value<R> {
|
||||
return s.map(k);
|
||||
}
|
||||
dictionary(d: Dictionary<Value<T>, T>, k: Fold<T, Value<R>>): Value<R> {
|
||||
dictionary(d: Dictionary<T>, k: Fold<T, Value<R>>): Value<R> {
|
||||
return d.mapEntries(([key, value]) => [k(key), k(value)]);
|
||||
}
|
||||
annotated(a: Annotated<T>, k: Fold<T, Value<R>>): Value<R> {
|
||||
|
@ -110,7 +110,7 @@ export function fold<T, R>(v: Value<T>, o: FoldMethods<T, R>): R {
|
|||
return o.array(v, walk);
|
||||
} else if (Set.isSet<T>(v)) {
|
||||
return o.set(v, walk);
|
||||
} else if (Dictionary.isDictionary<Value<T>, T>(v)) {
|
||||
} else if (Dictionary.isDictionary<T>(v)) {
|
||||
return o.dictionary(v, walk);
|
||||
} else if (Annotated.isAnnotated<T>(v)) {
|
||||
return o.annotated(v, walk);
|
||||
|
@ -153,7 +153,7 @@ export function isPointer<T>(v: Value<T>): v is T {
|
|||
},
|
||||
array(_a: Array<Value<T>>, _k: Fold<T, boolean>): boolean { return false; },
|
||||
set(_s: Set<T>, _k: Fold<T, boolean>): boolean { return false; },
|
||||
dictionary(_d: Dictionary<Value<T>, T>, _k: Fold<T, boolean>): boolean {
|
||||
dictionary(_d: Dictionary<T>, _k: Fold<T, boolean>): boolean {
|
||||
return false;
|
||||
},
|
||||
|
||||
|
|
|
@ -227,8 +227,8 @@ export class Reader<T> {
|
|||
}
|
||||
}
|
||||
|
||||
readDictionary(): Dictionary<Value<T>, T> {
|
||||
return this.seq(new Dictionary<Value<T>, T>(),
|
||||
readDictionary(): Dictionary<T> {
|
||||
return this.seq(new Dictionary<T>(),
|
||||
(k, acc) => {
|
||||
this.skipws();
|
||||
switch (this.peek()) {
|
||||
|
|
|
@ -26,13 +26,20 @@ export interface RecordConstructorInfo<L extends Value<T>, T = DefaultPointer> {
|
|||
arity: number;
|
||||
}
|
||||
|
||||
export type InferredRecordType<L, FieldsType extends Tuple<any>> =
|
||||
L extends symbol ? (FieldsType extends Tuple<Value<infer T>>
|
||||
? (Exclude<T, never> extends symbol ? Record<L, FieldsType, never> : Record<L, FieldsType, T>)
|
||||
: (FieldsType extends Tuple<Value<never>>
|
||||
? Record<L, FieldsType, never>
|
||||
: "TYPE_ERROR_cannotInferFieldsType" & [never])) :
|
||||
L extends Value<infer T> ? (FieldsType extends Tuple<Value<T>>
|
||||
? Record<L, FieldsType, T>
|
||||
: "TYPE_ERROR_cannotMatchFieldsTypeToLabelType" & [never]) :
|
||||
"TYPE_ERROR_cannotInferPointerType" & [never];
|
||||
|
||||
export function Record<L, FieldsType extends Tuple<any>>(
|
||||
label: L, fields: FieldsType):
|
||||
L extends Value<infer T>
|
||||
? (FieldsType extends Tuple<Value<T>>
|
||||
? Record<L, FieldsType, T>
|
||||
: never)
|
||||
: never
|
||||
label: L,
|
||||
fields: FieldsType): InferredRecordType<L, FieldsType>
|
||||
{
|
||||
(fields as any).label = label;
|
||||
return fields as any;
|
||||
|
|
|
@ -33,7 +33,7 @@ export function strip<T = DefaultPointer>(
|
|||
return (v.item as Value<T>[]).map(walk);
|
||||
} else if (Set.isSet<T>(v.item)) {
|
||||
return v.item.map(walk);
|
||||
} else if (Dictionary.isDictionary<Value<T>, T>(v.item)) {
|
||||
} else if (Dictionary.isDictionary<T>(v.item)) {
|
||||
return v.item.mapEntries((e) => [walk(e[0]), walk(e[1])]);
|
||||
} else {
|
||||
return v.item;
|
||||
|
|
|
@ -28,4 +28,4 @@ export type Compound<T = DefaultPointer> =
|
|||
// Value<T> to any.
|
||||
| Array<Value<T>>
|
||||
| Set<T>
|
||||
| Dictionary<Value<T>, T>;
|
||||
| Dictionary<T>;
|
||||
|
|
|
@ -140,7 +140,7 @@ describe('encoding and decoding pointers', () => {
|
|||
it('should store pointers embedded in map keys correctly', () => {
|
||||
const A1 = ({a: 1});
|
||||
const A2 = ({a: 1});
|
||||
const m = new Dictionary<number, object>();
|
||||
const m = new Dictionary<object, number>();
|
||||
m.set([A1], 1);
|
||||
m.set([A2], 2);
|
||||
expect(m.get(A1)).toBeUndefined();
|
||||
|
@ -157,7 +157,7 @@ describe('common test suite', () => {
|
|||
const samples = decodeWithAnnotations(samples_bin, { decodePointer: decodeDefaultPointer });
|
||||
|
||||
const TestCases = Record.makeConstructor<{
|
||||
cases: Dictionary<Value<DefaultPointer>, DefaultPointer>
|
||||
cases: Dictionary<DefaultPointer>
|
||||
}>()(Symbol.for('TestCases'), ['cases']);
|
||||
type TestCases = ReturnType<typeof TestCases>;
|
||||
|
||||
|
@ -257,7 +257,7 @@ describe('common test suite', () => {
|
|||
}
|
||||
|
||||
const tests = (peel(TestCases._.cases(peel(samples) as TestCases)) as
|
||||
Dictionary<Value<DefaultPointer>, DefaultPointer>);
|
||||
Dictionary<DefaultPointer>);
|
||||
tests.forEach((t0: Value<DefaultPointer>, tName0: Value<DefaultPointer>) => {
|
||||
const tName = Symbol.keyFor(strip(tName0) as symbol)!;
|
||||
const t = peel(t0) as Record<symbol, any, DefaultPointer>;
|
||||
|
|
Loading…
Reference in New Issue