Code Monkey home page Code Monkey logo

Comments (9)

gcanti avatar gcanti commented on May 17, 2024

Adding a _tag field to each *Type (a trick used in fp-ts) would allow for exhaustivity checks on custom defined unions

export class InterfaceType<P extends Props> extends Type<InterfaceOf<P>> {
+  readonly _tag: 'InterfaceType' = 'InterfaceType'
}

export class UnionType<RTS extends Array<Any>, U> extends Type<U> {
+  readonly _tag: 'UnionType' = 'UnionType'
}
type T = t.InterfaceType<any> | t.UnionType<any, any>

function f(type: T): string {
  switch (type._tag) {
    case 'InterfaceType':
      return 'interface'
    case 'UnionType':
      return 'union'
  }
}

from io-ts.

DylanRJohnston avatar DylanRJohnston commented on May 17, 2024

Is there any downside / upside to using any for the type parameters? Instead of trying to preserve the type information?

from io-ts.

gcanti avatar gcanti commented on May 17, 2024

I don't think there's any downside. If needed, types can also be extracted

const Person = t.interface({
  name: t.string
})

// type A = { name: t.Type<string>; }
type A = typeof Person.props

const U = t.union([t.string, Person])

// type B = [t.Type<string>, t.InterfaceType<{ name: t.Type<string>; }>]
type B = typeof U.types

// type C = t.Type<string>
type C = typeof U.types[1]['props']['name']

from io-ts.

gcanti avatar gcanti commented on May 17, 2024

to build database schemas and stuff from the Type definition

@DylanRJohnston That's interesting, could you elaborate and/or show some practical example (in order to make sure the change above will be effective)?

from io-ts.

DylanRJohnston avatar DylanRJohnston commented on May 17, 2024

I was thinking of something in the vein of the generic deriving from Haskell, so you could define a function that is able to compute a value from any Type representation. I'm trying to get it to generate a Sequelize schema object.

I think there's a problem with using the readonly _tag = StringLiteral when there's a Type that inherits from another type, e.g.

class Foo {
    readonly _tag = "Foo"
}

class Bar extends Foo {
    readonly _tag = "Bar"
}
Class 'Bar' incorrectly extends base class 'Foo'.
  Types of property '_tag' are incompatible.
    Type '"Bar"' is not assignable to type '"Foo"'.

from io-ts.

DylanRJohnston avatar DylanRJohnston commented on May 17, 2024

It'd also be ideal to be able to case match on the different Type<primitive types> types too. There's a cool library that uses class decorators to achieve the same thing. But we were hoping to stick with structural typing via interfaces instead of nominal typing via classes. Might have to bite the bullet and just use classes.

from io-ts.

DylanRJohnston avatar DylanRJohnston commented on May 17, 2024

I guess you could recover it by going

type ClassTags = "Foo" | "Bar"

interface HasTag {
    readonly _tag : ClassTags
}

class Foo {
    readonly _tag : ClassTags = "Foo"
}

class Bar extends Foo {
    readonly _tag = "Bar"
}

function isFoo(x : HasTag): x is Foo {
    return x._tag === "Foo";
}

function isBar(x : HasTag): x is Bar {
    return x._tag === "Bar";
}

const assertNever = (x: never): never => {throw new Error(x);}

function foobar(x : Foo | Bar) {
    if (isFoo(x)) {
        return ""
    } else if (isBar(x)) {
        return ""
    } else {
        return assertNever(x);
    }
}

from io-ts.

gcanti avatar gcanti commented on May 17, 2024

@DylanRJohnston You can find a proof of concept in the 50 branch

  • But to leverage totality checking I need to be able to form some kind of tagged union of the Types in this package
  • It'd also be ideal to be able to case match on the different Type types too
  • a Type that inherits from another type (<= Q: does this still make sense? Now types are structural)

Example

import * as t from 'io-ts'

type Primitive = t.StringType | t.NumberType
type Primitives = { [key: string]: Primitive }
interface Schemas extends Array<Schema> {}
type Union = t.UnionType<Schemas, any>

type Schema = t.InterfaceType<Primitives> | Union

declare function f(type: Schema): string

const A = t.interface({
  a: t.string
})

const B = t.interface({
  b: t.number
})

const C = t.interface({
  c: t.boolean
})

const D = t.union([A, B])
const E = t.union([A, C])

f(A)
f(B)
f(C) // error: Type '"BooleanType"' is not assignable to type '"NumberType"'.
f(D)
f(E) // error

Could you please try it out with your use case? lib is committed in so you can install it by running

npm i gcanti/io-ts#50

from io-ts.

DylanRJohnston avatar DylanRJohnston commented on May 17, 2024

Yes! Thank you so much. It works great.

from io-ts.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.