-
Notifications
You must be signed in to change notification settings - Fork 4
Upgrade TypeScript from 3.2.2 to 3.6.4 #7
base: master
Are you sure you want to change the base?
Conversation
c8e8352
to
2440cce
Compare
const pickTrueInObject = <K extends string>( | ||
obj: Partial<Record<K, boolean>>, | ||
): Partial<Record<K, true>> => | ||
pickBy(obj as Record<K, boolean>, (_key, value): value is true => value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit stuck here.
pickTrueInObject
must be allowed to receive partials. But if we update this function, we have to update every helper it uses internally (pickBy
and entries
) to also allow Partial
. That feels wrong :-/
@karol-majewski Any thoughts on what we should do here?
Complete example:
const keys = <O extends object>(obj: O) =>
Object.keys(obj) as Array<keyof O>;
const entries = <K extends string, V>(obj: Record<K, V>) =>
keys(obj).map(key => [key, obj[key]] as const);
const fromEntries = <K extends string, V>(arr: Array<[K, V]>) =>
Object.assign({}, ...arr.map(([k, v]) => ({ [k]: v }))) as Record<K, V>;
const pickBy = <K extends string, V, Result extends V>(
obj: Record<K, V>,
predicate: (key: K, value: V) => value is Result,
) =>
fromEntries(
entries(obj).filter((entry): entry is [K, Result] => {
const [key, value] = entry;
return predicate(key, value);
}),
);
const pickTrueInObject = <K extends string>(
obj: Record<K, boolean>,
): Partial<Record<K, true>> =>
pickBy(obj, (_key, value): value is true => value);
declare const record: Partial<Record<'foo' | 'bar', boolean>>;
// declare const record: Record<'foo' | 'bar', boolean>;
pickTrueInObject(record); // error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@karol-majewski Hey, do you have any thoughts on the above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the T
passed to pickTrueInObject
is a Dictionary<boolean>
, isn't it sufficient to say pickTrueInObject
will return a Partial<T>
?
Sure, the signature could be more precise:
declare function pickTrueInObject<T extends object>(source: T): Partial<Record<PropertyOfValue<T, boolean>, true>>;
type PropertyOfValue<T, V> = {
[K in keyof T]: T[K] extends V
? K
: never
}[keyof T];
declare const foo: {
foo: number;
bar: boolean;
}
let result = pickTrueInObject(foo); // { bar?: true }
but since we're not dealing with object literals, we cannot use the type system to tell us which properties will be true
in runtime and that renders having this extra information useless.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to pipe well.
import { pipe } from 'pipe-ts';
declare function pickTrueInObject<T extends object>(source: T): Partial<Record<PropertyOfValue<T, boolean>, true>>;
type PropertyOfValue<T, V> = {
[K in keyof T]: T[K] extends V
? K
: never
}[keyof T];
declare const foo: {
foo: number;
bar: boolean;
}
const UNSAFE_keys = <T extends object>(source: T) =>
Object.keys(source) as (keyof T)[];
const keys = pipe(pickTrueInObject, UNSAFE_keys)(foo); // "bar"[]
No description provided.