Fp-ts: Use `unknown` type instead of `{}` (TypeScript 3.0+)

Created on 28 Jul 2018  路  25Comments  路  Source: gcanti/fp-ts

Affected APIs

  • Either.toError
  • Either.tryCatch
  • IOEither.tryCatch
  • ReaderTaskEither.tryCatch
  • Task.tryCatch
  • TaskEither.tryCatch
new feature

Most helpful comment

I see, thanks for explaining. That's a bit hacky though and respect to {} would be a regression.

Another option is module augmentation: 2.9 users which want to upgrade to [email protected] could augment global

declare global {
  type unknown = {}
}

or even better

declare global {
  // how io-ts's `mixed` type is currently defined
  type unknown = { [key: string]: any } | object | number | string | boolean | symbol | undefined | null | void
}

All 25 comments

Does this break compatibility with TS<3.0?

@raveclassic I think so

Maybe we should move it to [email protected] then? Does it solve some issues with typings or is it just polishing?

Does it solve some issues with typings or is it just polishing?

unknown is the new safer way to type untrusted data

Maybe we should move it to [email protected] then?

That's an interesting (and maybe controversial) topic:

using new (type-level) features of the TypeScript compiler should be considered a breaking change?

IMHO What should be considered a breaking change is what requiers something to do (in addition to the upgrade) in order to keep the same behaviour.
On the other hand, doing a major make no sense at all product wise..
Yes, it's controversial.

IMHO we should do a major as @sledorze said there will be code changes to me made. Aren't there any other breaking changes hold back for the next major? This would be the time to think about.

On the other hand, doing a major make no sense at all product wise

I agree.

(I wonder what's the policy used by other TypeScript libraries)

a breaking change is what requiers something to do (in addition to the upgrade) in order to keep the same behaviour

More specifically, is this the case? {} in those APIs must be refined as much as unknown

(same for mixed in io-ts)

@gcanti I have no idea, I'm a bit under the water (and in the heat) those days..
Maybe @mlegenhausen has already tried it?

I just changed the {} to unknown in my node_modules .d.ts files and everything worked out of the box with [email protected]. They alias unknown with any. So changes in [email protected] code should not need to be made.

So it seems not to be a breaking change at all. Can someone confirm?

@mlegenhausen I can't confirm, using v2.9.2 if I type

type A = unknown

I get

[ts] Cannot find name 'unknown'.

Ok can confirm the error now. ts-node does not output any error. tsc does. Still buildable but with error output on the console. When you use fp-ts as library the signature changes as said to any type cause the type can not be found.

I see, thanks for explaining. That's a bit hacky though and respect to {} would be a regression.

Another option is module augmentation: 2.9 users which want to upgrade to [email protected] could augment global

declare global {
  type unknown = {}
}

or even better

declare global {
  // how io-ts's `mixed` type is currently defined
  type unknown = { [key: string]: any } | object | number | string | boolean | symbol | undefined | null | void
}

Seems like this should be added on top of every module which uses unknown, then we can consider this non-breaking change, right?

@raveclassic nope, module augmentation should be done in userland: do you want to upgrade to [email protected] and keep using <= [email protected]? Ok, put this

declare global {
  type unknown = {}
}

somewhere in your app

Well, that's a breaking change then

Yes, perhaps a little, sensible, easy fixable breaking change, but still a breaking change.

So looks like there's only one option

release a major version everytime a new feature is used

That's not desiderable though, given that TypeScript doesn't follow semver and its release pace. For example let's say we merge this PR and release [email protected] then, since mapped tuples are on their way (just found out) and they could be useful to improve compose and pipe, the risk is that we are going to release [email protected] soon afterward.

So if we want to avoid releasing major versions too frequently (and I do), we should "freeze" fp-ts and stick to [email protected] features (as far as I know).

Another proposal:

stick to [email protected] features

In order to avoid stagnation, how do you feel about supporting last 2 stable releases?

For example currently latest release is 3.0.1 so fp-ts should support 2.9.2 and 3.0.1. When 3.1.0 will be released, fp-ts will support 3.0.1 and 3.1.0.

Well TS team releases a minor each two months (at least they try), so the last 2 stable releases will last for 4 months. I think it's not enough for fp-ts support schedule.

Interesting PR ("Adds support for "typesVersions" redirects") https://github.com/Microsoft/TypeScript/pull/26568

Hi @gcanti,

I'm also struggling with the newest TypeScript v3.0.x release.

const validate = (error: string) => <T>(v: T): Either<sting, T> =>
  v === undefined || v === null
    ? left(error)
    : right(v)

Lets say that we have a path: string to validate

right(path)
  .chain(validate('Path cannot be empty))
  .fold(
    error => doSomethinWithError(error),
    path => doSomethingWithPath(path),
  );

The chain method infers the returned type to Either<{}, string}> instead of Either<string, string> which is explicitly returned via validate function. This way error parameter is inferred as {} type` Is it really the TS issue?

@JozefFlakus currently you have to add an explicit annotation at the call site

right<string, string>(path)
  .chain(...)

p.s.
Btw validate looks a lot like fromNullable

import { fromNullable } from 'fp-ts/lib/Either'

@gcanti with the release of typesVersions this can now be a non-breaking change, can't it?

@mmkal yes, I just published https://github.com/gcanti/unknown-ts which exports

  • mixed = { [key: string]: any } | object | number | string | boolean | symbol | undefined | null | void for older typescript versions
  • mixed = unknown for >=3.1

I'm going to add unknown-ts as a dependency and publish a patch release

Forget it.
It doesn't work.

When producing the declaration files typescript resolves the imported mixed type with unknown, thus rendering the entire workaround useless.

Ok I give up, I'll go with @mlegenhausen 's suggestion here

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mustafaekim picture mustafaekim  路  4Comments

FredericLatour picture FredericLatour  路  3Comments

maciejsikora picture maciejsikora  路  3Comments

miguelferraro picture miguelferraro  路  3Comments

Crashthatch picture Crashthatch  路  4Comments