4 ms·
In this case not even TypeScript can rescue you. You might naively implement: const head = (input: A[]) => input[0] and it will happily infer a return typ
by ricardobeat 7y ago
In this case not even TypeScript can rescue you. You might naively implement:
const head = (input: A[]) => input[0]
and it will happily infer a return type of A. Then you'll fall flat on your face the first time you encounter an empty array:
head([]) // -> undefined
To make it correct you need to explicitly define a return type of (input: A[]): A | undefined, just as the Maybe. It's obviously impossible for TS to guarantee that an array will not be empty at runtime, but I wish this specific case triggered some help from the type checker.
- tylerhou 7y ago> It's obviously impossible for TS to guarantee that an array will not be empty at runtime, but I wish this specific case triggered some help from the type checker. type NonEmptyArray<T> = { head: T, rest: T[] }; function makeNonEmptyArray<T>(array: T[]): NonEmptyArray<T> | null { if (array.length == 0) return null; return { head: array[0], rest: array.slice(1, array.length) }; } function head<T>(array: T[]): T | null; function head<T>(array: NonEmptyArray<T>): T; function head(array: any): any { if (Array.isArray(array)) { if (array.length === 0) return null; return array[0]; } if (typeof array === "object") { return array.head; } } http://www.typescriptlang.org/play/#code/C4TwDgpgBAcg9gOwKIFsygIICcsEMQA8AKgHxQC8UA3lABYS4AmAXFEQDRRYQDOwrRANoBdKAF8A3ACgpAMwCuCAMbAAloigpcAawjxkaTDnzESAClzGQAkQEpW+1OhDY8hUlAA+UBPIA2ftRSUFCqslAWVgB0fhAIAObAtBSUAAy2XBDA8lgIPv5+0iHc2bnUdAwsUJZugqnCnNx8rDX4UTx+qkoQZgCMnK0gMXGJtBmSUmIyCspqGvRMppFuNsL2bF75AdIzKup5C4xLgw6ITkZuputEO4p785XL+C0IIOu4r0EhYRGubao8P4gJ5vDJUYIhULhEHDBJJFJpDIlHJ5XzbCHFLIo6pWOrCIriGTfaGgSBwcKDBFQABEcAARgArCAqalgjGZUp5QZRQ4EqZiIA http://www.typescriptlang.org/play/#code/C4TwDgpgBAcg9gOwKIF... It's impossible for Haskell to guarantee an array will not be empty at runtime as well; that's why we can write a new type + a smart constructor to track runtime properties.
- s_severus 7y agoA possibly more elegant TypeScript solution: type NonEmpty<T> = [T, ...T[]]; function head<T>(input: NonEmpty<T>): T { return input[0]; } https://www.typescriptlang.org/play/?ssl=5&ssc=2&pln=1&pc=1#code/C4TwDgpgBAcg9gOwKIFsygDwBUB8UC8UA2lgDRQB0VWRAurQNwCwAUKwGYCuCAxsAJaIoACwgBDACbYcACn4IwnYAC5YiVOhDSAlKqxQA3qyhQAThGCdTCKPMXAiABkasAvq1ajJMutuYsAegCoAEFTAHNOFAgEYCg4dihQSCgAcjpU2wBnKAQ4OLEsrP5whDEAIwAbaGA4KDAxUzFo4AhTeMTk6FT4ZDRMbgBrPIB3BBxUilYgkwAFUzhIU1A0x0z+HJQN4oRw2xsutIyocqUzCABHTn5zCX2k8G7ejQGEYbgxiam2Fi8JHwATLQ-FAZnBBgBCDwsHiILJxBBRcptLKqREoZGmOgEYgARhcv3E-3RmKyfmmwTCkWisQ6DxSqRJbWOG1y+SghWKpQq1SSdQaTRabTphx66n6WiZpi+0NhCHhbL6mhgSJRqmeEowUrwhCI+P8fxkeSVoBVGJRILBkKAA https://www.typescriptlang.org/play/?ssl=5&ssc=2&pln=1&pc=1#...
- nikeee 7y ago> It's obviously impossible for TS to guarantee that an array will not be empty at runtime, Maybe you could use "Rest elements in tuple types" and do an overloaded signature like this: function head<T>(...args: [T, ...any[]]): T; function head<T>(...args: []): undefined function head<T>(...args: [T, ...any[]] | []): T | undefined { return args[0]; } (not tested) You'd have to spread the arguments or use call/bind/apply, though. [1]: https://github.com/microsoft/TypeScript/pull/24897 https://github.com/microsoft/TypeScript/pull/24897