3 ms·
How do you verify it now? I've been using typeguards, but since i haven't found a good way to generate interfaces from typeguard functions or typeguard function
by joshAg 7y ago
How do you verify it now? I've been using typeguards, but since i haven't found a good way to generate interfaces from typeguard functions or typeguard functions from interfaces I have to do each manually:
interface ContactInfo {
address_1: string;
address_2?: string;
city: string;
state: string;
zip: string;
phone: number;
}
function isContactInfo(arg: any): arg is ContactInfo {
let valid = false;
const contactInfoFields: { readonly [key: string]: string[] } = {
address_1: [ 'string', ],
address_2: [ 'string', 'undefined' ],
city: [ 'string', ],
state: [ 'string', ],
zip: [ 'string', ],
phone: [ 'number' ],
};
if (typeof arg !== 'object') {
return valid;
}
for (const key in contactInfoFields) {
if(!contactInfoFields[key].includes(typeof arg[key]) || arg[key] === '' || Number.isNaN(arg[key])) {
return valid;
}
}
valid = true;
return valid;
}
- frankpf 7y agoNot related to the new assert signatures feature (which is great!), but IMO the two best approaches to do what you want today are: - io-ts[1] This requires you to write your types as a runtime value, and allows you to extract static types from those, e.g.: const ContactInfo = t.type({ address_1: t.string, ... }) type ContactInfo = t.TypeOf<typeof ContactInfo> You can validate objects with `ContactInfo.decode(someObject)` Note that we can have the same name for the type and value because they live in different namespaces. When you do ContactInfo.decode, you're calling the decode property of `const ContactInfo`. When you use `ContactInfo` in a type position (e.g. `function x(arg: ContactInfo)`), you're using the `type ContactInfo` declaration - typescript-is[2] This uses TypeScript's transformer API. You can use it with https://github.com/cevek/ttypescript https://github.com/cevek/ttypescript. It generates validators for your interfaces/types/etc at compile-time. [1]: https://github.com/gcanti/io-ts https://github.com/gcanti/io-ts [2]: https://github.com/woutervh-/typescript-is https://github.com/woutervh-/typescript-is
- joshAg 7y agotypescript-is looks like it can be a drop-in solution since we're only dealing with PODS. Thanks!
- moltar 7y agoCheck runtypes module.
- alangpierce 7y agoIn addition to the suggestions in the sibling comments, I've had good luck with ts-interface-checker/ts-interface-builder . You add a code generation step to your build process (rather than ttsc) that generates runtime equivalents of your TS types, and there's a library to perform a runtime check. https://github.com/gristlabs/ts-interface-checker https://github.com/gristlabs/ts-interface-checker
- jakelazaroff 7y agoYou can extract a type from a typeguard using a conditional type! type TypeOf<T> = (x: any) => x is (infer U) ? U : never; I wrote a really small and simple validator library called narrows that works this way [1]. You could simplify your code like so: import { number, optional, record, string, TypeOf } from 'narrows'; const isContactInfo = record({ address_1: string, address_2: optional(string), city: string, state: string, zip: string, phone: number }) type ContactInfo = TypeOf<typeof isContactInfo>; The source is less than 50 lines and super readable if you want to dig in. The libraries in the sibling comments are great too! [1] https://www.npmjs.com/package/narrows https://www.npmjs.com/package/narrows
- joshAg 7y agoI've been hesitant to switch to something that demands custom type declarations, because we're already autogenerating a lot of types/interfaces with express-openapi (we lean heavily on their request and response validators, too but those don't cover all the types we make), and getting that to play nicely with custom declarations is not my idea of fun. But for the types that aren't tied back to an json-endpoint (we have a few endpoints where we're getting xml or csv or xlsx and a few db<-->backend only interfaces), this looks like a great solution. Typescript-is looks like it might have an overall edge, though, because we can use it on the autogenerated types as well with almost no hassle.