Extends
type test0 = Extends<any, any> // boolean
type test0 = Extends<any, any> // true
@regevbr discovered this bug https://github.com/microsoft/TypeScript/issues/30188#issuecomment-506041815
@regevbr, thanks for reporting this first bug. From now on, don't hesitate to open issue, bug or feature request. Happy coding!
@pirix-gh thanks for the swift fix!
@pirix-gh this still doesn't work for me... (v2.0.14)
import { Object, Any } from 'ts-toolbelt';
export function getProp<O extends object, P extends string[]>(obj: O,
...keys: Any.Cast<P, Object.PathValid<O, P>>)
: Object.Path<O, P> {
return keys.reduce(
(result: any, key: string) => (result === null || result === undefined) ? undefined : result[key],
obj);
}
const o1: any = { a: { b: { c: 100 } } } ;
const t0 = getProp(o1, 'a', 'b', 'c');
// Argument of type '"a"' is not assignable to parameter of type 'HasPath<any, ["a"], any, "default"> extends true ? "a" : never'.
@regevbr, your error message looks odd. I get no errors on TS 3.5, 3.6
There is no support for TS below 3.5. What is your environment (TS, IDE) ?

@pirix-gh I was using 3.4.5 because of breaking changes that were introduced in 3.5 (the deep nesting error). I just upgraded to 3.5.2 and indeed it works!
Thanks!
Cool! We started support at 3.5 because of this breaking change https://github.com/microsoft/TypeScript/pull/30769
Which allowed me to improve performance very much (indexes)
I will update the Readme to mention more clearly the non-support
Happy coding
@regevbr I've just released v2.1, including performance improvements for PathValid
@pirix-gh thanks! saw what you did there - stopped the iteration once you hit a block - nice!
Can you please explain this line though :
https://github.com/pirix-gh/ts-toolbelt/blob/c0287eb0a8b51383b6fc1b5910a412d4dc7071b0/src/Object/PathValid.ts#L26
In short, let's say you have an object O and a path ['a', 'b', 'c']
type O = {
a: {
b: {
c: {}
}
}
}
Instead of trying all possible paths like before (heavy), PathValid now follows a given path and stops when it's wrong, then fills whatever is left with never. So it stops, and to do so, it follows your path:
// We use `At` to do the following
type test0 = O['a']['b']['x']
// But `At` never fails, it rather returns `never`
So if we dive in O, and the path is wrong (or finished) it will end up being never.
Then you might wonder why use brackets? Because if you don't use them and O (like O['a' | 'b']) is an union then the union will get distributed. But I don't what that, I want to match a specific condition. It might not be useful in this case (because I match never), but it clearly indicates that I do not want to distribute it.