Git Product home page Git Product logo

any-ts's Introduction


๐—ฎ๐—ป๐˜†-๐˜๐˜€


NPM Package

any-ts is a small set of TypeScript namespaces that overload built-in names (like any) to make them extensible.

Note

Currently, any-ts is BYOI: "bring your own implementation". With the exception of the ANY_TS_VERSION constant, any-ts only ships type declarations.

Requirements

What problem does any-ts solve?

The reason any-ts exists is because TypeScript types are hard to get right.

The TypeScript team has invested a lot of time into making their syntax beginner friendly, and easy to use.

The problem, as anyone who's used TypeScript for some time knows, is that while the type system is incredibly powerful, it's also incredibly ๐Ÿฆ„ magical ๐ŸŒˆ.

I think most TS users would agree:

While TypeScript is, in some ways, "easy" to use, it's not simple.

Some of this complexity, we feel, is avoidable. Let's look at an example.

Let's say you're writing a small library of helper functions:

/**
 * `identity` is a function that takes any arbitrary input, captures as much type
 * information as possible, and returns it to you:
 */
const identity = <const type>(term: type): type => term

/** `flatten` is a variadic function that takes a list of arrays and... well, flattens them. */
const flatten = <const T extends Array<Array<any>>>(...arrays: T) => arrays.flat()

You write some tests, everything works as expected, so you ship it. Nice work!

But before long, someone creates an issue. Here's what they tried to do:

import { identity, flatten } from "helpful-helpers"

const arr1 = identity([0, 1, 2, 3])
const arr2 = identity([4, 5, 6, 7])

const arr3 = flatten(arr1, arr2)
//                   ^^^^ ๐Ÿšซ TypeError

Can you spot the problem?

The problem here is that arr1 has the type readonly [1, 2, 3], and flatten only accepts mutable arrays.

You do some research and find it that every ReadonlyArray, despite having the longer, more "qualified" name, does not extend Array.

In fact, it's actually the other way around: every Array is a structural subtype of ReadonlyArray.

Here's how any-ts solves this problem:

import type { any } from "any-ts"

const identity = <const type>(term: type): type => term

const flatten = <const T extends any.array<any.array>>(...arrays: T) => arrays.flat()

const arr1 = identity([0, 1, 2, 3])
const arr2 = identity([4, 5, 6, 7])

flatten(arr1, arr2)
// no type error

What's happening?

If you're troubled by the any.array<any.array> syntax, don't worry: it's not as cursed as it might sound.

But how are you adding properties to any, as if it were an object?

The short answer is that types and namespaces can share identifiers. This has been the case for years. And unlike objects, namespace can export types.

All we've done is overload any, which allows us to piggyback on its semantics. any is still any, and any.array is a type that absorbs the complexity (and verbosity) of readonly unknown[].

But what if I want an array of strings?

import type { any } from "any-ts"

type myStringArray = any.array<string>
//   readonly string[]

But what if I want a mutable array?

With any-ts, your intent is explicit:

import type { any, mut } from "any-ts"

type myMutableArray = mut.array
//   ^? type myMutableArray = unknown[]
type myMutableStringArray = mut.array<string>
//   ^? type myMutableStringArray = string[]

// or, if you prefer not importing both:
type myOtherArray = any.mut.array
//   ^? type myOtherArray = unknown[]

type myOtherStringArray = any.mut.array<string>
//   ^? type myOtherStringArray = string[]

But what if I want to express more advanced types?

In our opinion, this is where any-ts really shines.

If you're a power user, you can do some pretty cool things with any-ts. Let's continue using any.array, even though it's one of the simplest types the library implements.

What if you wanted to extract (or pattern-match) the type that an array holds?

declare namespace Dictionary {
  type fromArray<xs extends any.array> 
    = xs extends any.array<infer x> ? Record<string, x> : never;
}

type featureFlags = Dictionary.fromArray<boolean[]>
//   ^? type featureFlags = Record<string, boolean>

Of the hundreds of types that any-ts ships, almost all of them can be used in matching position, like above.

If you're looking for more examples, you can find more in the examples directory (WIP).

Looking for something that we don't ship yet? Raise an issue -- we'd love to try to help!

Namespaces

any-ts's People

Contributors

ahrjarrett avatar github-actions[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

any-ts's Issues

set up release pipeline

currently we have changesets installed, but aren't leveraging it (or any CI/CD pipeline at all, really).

set up a github action that automates the release process.

remove tsup

we don't actually need commonjs/esm exports. shipping runtime code shouldn't theoretically affect users' bundle size, but that assumes that they've installed as a dev dependency.

better that we don't assume anything.

bug: account for contravariace in index signature in `any.dict`

Right now, any.dict's index signature is initialized as keyof never, which is the same as string | number | symbol.

That was a mistake on my part -- somewhat counter-intuitively, adding symbol to any.dict's signature causes its least upper bound to be too restrictive when it's used in covariant position.

`Kind.apply` and `Kind.bind` apply the wrong constraints

import type { any, Kind } from "any-ts"

interface ShowNumeric extends Kind<[number]> { [-1]: `${this[0]}` }

type three = Kind.apply<ShowNumeric, [10]>
//                                    ^^ applies `{ [ix in Extract<keyof ShowNumeric, `${number}`>]: ShowNumeric[ix] }` 

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.