[Discuss] Consider tradeoffs between 0-overhead and string verification
- Dominant language
- TypeScript
- Stars
- 1.2k
- Forks
- 57
- PR merge metrics
- No merged PRs in 30d
Description
With `schema-dts` v1, we already know to return compile errors for:
```ts
import { Number, Integer, Float } from 'schema-dts';
const a: Number = ''; // error
const b: Number = 'z'; // error
const c: Number = '5'; // success
const d: Number = '5.323'; // success
const e: Number = '534553.' // success
const f: Number = '.534553' // success
const g: Number = '4943.4433' // error
const h: Number = '43545ax' // error
const i: Number = '0x324' // success
const j: Number = '0x234deadbeef' // success
const k: Number = '0x123z' // error
// Same with types Integer and Float
```
But we don't yet verify that integers really are integers, for example:
```ts
const i: Integer = '5.5'; // success, should be error
```
I've been trying different strategies to make sure the `Integer` type can complain about `5.5` natively, but I can only come up with constructs where **a function argument** is vetted for being an integer string.
I.e., I can write this code that lets us do this:
```ts
import {Integer, VettedIntegerString, intString, hexString} from 'schema-dts';
const a: VettedIntegerString = intString(''); // error
const b: VettedIntegerString = intString('a'); // error
const c: VettedIntegerString = intString('abc'); // error
const d: VettedIntegerString = intString('5'); // success
const e: VettedIntegerString = intString('55'); // success
const a2: VettedIntegerString = hexString('0x'); // error
const b2: VettedIntegerString = hexString('0xa'); // success
const c2: VettedIntegerString = hexString('0xabc'); // success
const d2: VettedIntegerString = hexString('0x5'); // success
const e2: VettedIntegerString = hexString('0x55'); // success
const e2: VettedIntegerString = hexString('55'); // error
// where using `Integer` instead of VettedIntegerString also works:
const xa: Integer = intString(''); // error
const xb: Integer = intString('a'); // error
const xc: Integer = intString('abc'); // error
const xd: Integer = intString('5'); // success
const xe: Integer = intString('55'); // success
const xa2: Integer = hexString('0x'); // error
const xb2: Integer = hexString('0xa'); // success
const xc2: Integer = hexString('0xabc'); // success
const xd2: Integer = hexString('0x5'); // success
const xe2: Integer = hexString('0x55'); // success
const xe2: Integer = hexString('55'); // error
// but also:
const i: Integer = 5; // works
```
The code would look like this:
```ts
const Integer_Type_Is_Constructed_With_intString_Or_hexString_Helper_Function =
Symbol(
'Verified Integer String (this value never used, only its type is used in compilation)',
);
type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
type HexDigit =
| Digit
| 'a'
| 'b'
| 'c'
| 'd'
| 'e'
| 'f'
| 'A'
| 'B'
| 'C'
| 'D'
| 'E'
| 'F';
type IntegerString = T extends `${Digit}${infer Rest}`
? Rest extends ''
? T
: IntegerString
: never;
type HexSequence = T extends `${HexDigit}${infer Rest}`
? Rest extends ''
? T
: HexSequence
: never;
type HexString = T extends `0x${infer Rest}`
? HexSequence extends never
? never
: T
: never;
type WhenExists = Existence extends never ? never : T;
export function intString(
t: WhenExists, T>,
): T & {
[tag in typeof Integer_Type_Is_Constructed_With_intString_Or_hexString_Helper_Function]: true;
} {
return t as unknown as T & {
[tag in typeof Integer_Type_Is_Constructed_With_intString_Or_hexString_Helper_Function]: true;
};
}
export function hexString(
h: HexString,
): T & {
[tag in typeof Integer_Type_Is_Constructed_With_intString_Or_hexString_Helper_Function]: true;
} {
return h as unknown as T & {
[tag in typeof Integer_Type_Is_Constructed_With_intString_Or_hexString_Helper_Function]: true;
};
}
export type VettedIntegerString = string & {
[tag in typeof Integer_Type_Is_Constructed_With_intString_Or_hexString_Helper_Function]: true;
};
```
But this would be the first case where valid inline JSON-LD could not be verified. I.e. all string assignments to `Integer` would begin failing unless they were computed with `intString()` and `hexString()`.
Should we wait until a better option becomes expressible in the language, or is this an improvement as-is?
Contributor guide
Assessment
This issue has not been assessed yet.