From ecedb2e02451fb18ade5888d24e09956754accea Mon Sep 17 00:00:00 2001 From: ersimont <8042088+ersimont@users.noreply.github.com> Date: Tue, 24 Nov 2020 21:04:29 -0500 Subject: [PATCH] feat(micro-dash): improve the typing of `pick()` --- .../micro-dash/src/lib/object/pick.spec.ts | 6 --- projects/micro-dash/src/lib/object/pick.ts | 12 ++--- .../src/typing-tests/object/pick.dts-spec.ts | 54 +++++++++++++++++++ 3 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 projects/micro-dash/src/typing-tests/object/pick.dts-spec.ts diff --git a/projects/micro-dash/src/lib/object/pick.spec.ts b/projects/micro-dash/src/lib/object/pick.spec.ts index cbb5a85a..767d83fc 100644 --- a/projects/micro-dash/src/lib/object/pick.spec.ts +++ b/projects/micro-dash/src/lib/object/pick.spec.ts @@ -1,12 +1,6 @@ import { pick } from './pick'; describe('pick()', () => { - it('fancily narrows types', () => { - let picked: { a: number; b: string }; - picked = pick({ a: 1, b: 'b', c: { d: 3 } }, 'a', 'b'); - expect(picked).toEqual({ a: 1, b: 'b' }); - }); - // // stolen from https://github.com/healthiers/mini-dash // diff --git a/projects/micro-dash/src/lib/object/pick.ts b/projects/micro-dash/src/lib/object/pick.ts index 49320c75..1da291ed 100644 --- a/projects/micro-dash/src/lib/object/pick.ts +++ b/projects/micro-dash/src/lib/object/pick.ts @@ -1,4 +1,4 @@ -import { Nil } from '../interfaces'; +import { IfCouldBe, Nil } from '../interfaces'; /** * Creates an object composed of the picked `object` properties. @@ -10,14 +10,14 @@ import { Nil } from '../interfaces'; * - Lodash: 7,718 bytes * - Micro-dash: 142 bytes */ -export function pick( - object: T | Nil, - ...paths: K[] -): T extends Nil ? {} : Pick { +export function pick>>( + object: T, + ...paths: P +): { [K in P[number]]: NonNullable[K] } | IfCouldBe { const result: any = {}; if (object != null) { for (const path of paths) { - result[path] = object[path]; + result[path] = object[path as keyof T]; } } return result; diff --git a/projects/micro-dash/src/typing-tests/object/pick.dts-spec.ts b/projects/micro-dash/src/typing-tests/object/pick.dts-spec.ts new file mode 100644 index 00000000..22cffdd6 --- /dev/null +++ b/projects/micro-dash/src/typing-tests/object/pick.dts-spec.ts @@ -0,0 +1,54 @@ +import { pick } from '../../lib/object'; + +declare const str: string; +declare const num: number; + +declare const obj: { + a: number; + b: Date; +}; +// $ExpectType { b: Date; } +pick(obj, 'b'); + +declare const objOrNull: typeof obj | null; +declare const objOrUndefined: typeof obj | undefined; +declare const objOrNil: typeof obj | null | undefined; +// $ExpectType {} | { b: Date; } +pick(objOrNull, 'b'); +// $ExpectType {} | { b: Date; } +pick(objOrUndefined, 'b'); +// $ExpectType {} | { b: Date; } +pick(objOrNil, 'b'); + +declare const indexed: { + [k: string]: number; + [k: number]: number; +}; +// $ExpectType { hi: number; } +pick(indexed, 'hi'); +// $ExpectType { 5: number; } +pick(indexed, 5); +// $ExpectType { hi: number; 5: number; } +pick(indexed, 'hi', 5); +// $ExpectType { [x: string]: number; } +pick(indexed, str); + +declare const record: Record; +// $ExpectType { [x: string]: number; } +pick(record, str); + +declare const composite: { + [k: number]: Date; + a: 'eh'; + b: 'bee'; +}; +// $ExpectType { a: "eh"; } +pick(composite, 'a'); +// $ExpectType { a: "eh"; b: "bee"; } +pick(composite, 'a', 'b'); +// $ExpectType { 1: Date; } +pick(composite, 1); +// $ExpectType { [x: number]: Date; } +pick(composite, num); +// $ExpectType { [x: number]: Date; a: "eh"; } +pick(composite, num, 'a');