Ts-toolbelt: Why using `string` rather than `keyof O` in Omit/Pick/etc?

Created on 6 Jul 2019  路  11Comments  路  Source: millsp/ts-toolbelt

馃 Question

I get type errors unless I set my Typescript to skipLibCheck. Specifically around the types that operate on keys.

For example Omit is defined as:

export type Omit<O extends object, K extends string> =
    Pick<O, Exclude<keyof O, K>>

Why do you not use a keyof based restriction?

i.e.

export type Omit<O extends object, K extends keyof O> =
    Pick<O, Exclude<keyof O, K>>

You are obviously a Typescript god, so I assume there must be a solid reason for this decision?

bug question

Most helpful comment

Hi, dear bug reporters @regevbr @ctrlplusb @tonivj5 :bug:

I've published the latest version. I'd be thankful if you can install it and give me your feedback:
npm i ts-toolbelt@next --save

This version brings out:

  • Increased performance
  • 100% type soundness
  • Breaking API changes
  • No packed errors #15

However, these breaking changes don't affect Tuple, Union or Object and concern only String, Number, Boolean & some of the Function types that were renamed.

About this issue (#15). Nothing really changes, errors are still gracefully handled but instead of string you can now pass an Index which is string | number | symbol. And this works everywhere and with paths as well.

Index the next days, I will focus on the docs, tests and your feedback. Then release this v3 :tada:

Thanks!

All 11 comments

Hi @ctrlplusb,

No no no, this is a problem :laughing: !

However, it has/had a purpose:

  • You can pass any string value and the error will be gracefully handled for you
  • You can pass another type that can compute the keys for you without casting

Which is a problem if you use number indexes in objects and is a design problem (from my side) that was introduced since https://github.com/microsoft/TypeScript/pull/23592. For info, at that time I was starting to design this library.

But I will be fixing this in the v3 (soon). So in the mean time, if you can add this to your tsconfig.json:
"keyofStringsOnly": false "keyofStringsOnly": true

Thank you very much!

Hi, dear bug reporters @regevbr @ctrlplusb @tonivj5 :bug:

I've published the latest version. I'd be thankful if you can install it and give me your feedback:
npm i ts-toolbelt@next --save

This version brings out:

  • Increased performance
  • 100% type soundness
  • Breaking API changes
  • No packed errors #15

However, these breaking changes don't affect Tuple, Union or Object and concern only String, Number, Boolean & some of the Function types that were renamed.

About this issue (#15). Nothing really changes, errors are still gracefully handled but instead of string you can now pass an Index which is string | number | symbol. And this works everywhere and with paths as well.

Index the next days, I will focus on the docs, tests and your feedback. Then release this v3 :tada:

Thanks!

Amaze, thanks @pirix-gh, I will try this out and feedback asap. 馃憤

Wow 馃槏- works perfectly. I have a pretty extensive set of tests around my Typescript definitions too on my lib.

No errors, and I am doing full lib checking too.

Thanks for looking into this so fast!

I know how stressful maintaining a lib is, and can only imagine the complexity of managing a lib that operates on a typing system is exponentially more difficult. Huge kudos to you, and don't burn yourself out! 鉂わ笍

@ctrlplusb thank you a lot. And thanks for your tests too, this is really coool :sunglasses:.

Yhea, sometimes I feel a bit burnt out but then I think that it is a good return on investment as I will be less likely to burn out on my future projects if they are strongly typed. Then I feel much better :laughing:

Hi @pirix-gh I have just installed the latest version (3.0.0-6) and using it with ts 3.5.2 and the following example fails :-(

import { Object, Any, Union } from 'ts-toolbelt';

export function getProp<O extends object, P extends string[]>(obj: Union.Nullable<O>,
                                                              ...keys: Any.Cast<P, Object.PathValid<O, P>>)
  : Object.Path<O, P> | undefined {
  return keys.reduce(
    (result: any, key: string | number | symbol) => (result === null || result === undefined) ? undefined : result[key],
    obj);
}

interface IFoo {
  a: {
    b: {
      c: number;
    };
  };
}

const a: IFoo = undefined as unknown as IFoo;
getProp(a, 'a', 'b', 'c'); // works fine  - number | undefined
getProp(a as any, 'a', 'b', 'c'); // error TS2589: Type instantiation is excessively deep and possibly infinite.

Seems to be an issue with handling the any type.
Can you please check why that happens?

Hey @regevbr, glad to see you again!

It's been fixed, I added the tests this time so this won't happen again. Sorry for this!

I invite you to update :timer_clock:

@regevbr I updated again, reverting the At type to what it used to be. The At type caused TS to hang when used in recursive types. I blame it on an inconsistency from TypeScript's side.

For more details https://stackoverflow.com/questions/56942865/is-it-correct-that-anynever-is-of-type-any

@pirix-gh thanks! it is working now (or at least for now :-) ) will keep you posted as I migrate more projects

@pirix-gh upgraded in some more projects and it seems to work well :-) thanks!

Thanks again @regevbr for your help. I'm so glad it's all ok :tada:

Have a nice day

Was this page helpful?
0 / 5 - 0 ratings