Skip to content

Commit 40efe19

Browse files
committed
Deprecation
- deprecate `any` - deprecate `object` - deprecate `Dictionary` in favour of `UnknownRecord` - deprecate `Array` in favour of `UnknownArray` - deprecate `dictionary` in favour of `record`
1 parent 97b11bf commit 40efe19

File tree

7 files changed

+157
-134
lines changed

7 files changed

+157
-134
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@
1414
**Note**: Gaps between patch versions are faulty/broken releases. **Note**: A feature tagged as Experimental is in a
1515
high state of flux, you're at risk of it changing without notice.
1616

17+
# 1.7.1
18+
19+
- **Deprecation**
20+
- deprecate `any` (@gcanti)
21+
- deprecate `object` (@gcanti)
22+
- deprecate `Dictionary` in favour of `UnknownRecord` (@gcanti)
23+
- deprecate `Array` in favour of `UnknownArray` (@gcanti)
24+
- deprecate `dictionary` in favour of `record` (@gcanti)
25+
1726
# 1.7.0
1827

1928
- **New Feature**

README.md

+53-60
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,15 @@ Also a codec can
1616
- be used as a custom type guard (through `is`)
1717

1818
```ts
19-
export type mixed = unknown
20-
21-
class Type<A, O = A, I = mixed> {
19+
class Type<A, O, I> {
2220
readonly _A: A
2321
readonly _O: O
2422
readonly _I: I
2523
constructor(
2624
/** a unique name for this codec */
2725
readonly name: string,
2826
/** a custom type guard */
29-
readonly is: (v: mixed) => v is A,
27+
readonly is: (u: unknown) => u is A,
3028
/** succeeds if a value of type I can be decoded to a value of type A */
3129
readonly validate: (input: I, context: Context) => Either<Errors, A>,
3230
/** converts a value of type A to a value of type O */
@@ -47,22 +45,14 @@ A codec representing `string` can be defined as
4745
```ts
4846
import * as t from 'io-ts'
4947

50-
// codec definition
51-
export class StringType extends t.Type<string> {
52-
// equivalent to Type<string, string, mixed> as per type parameter defaults
53-
readonly _tag: 'StringType' = 'StringType'
54-
constructor() {
55-
super(
56-
'string',
57-
(m): m is string => typeof m === 'string',
58-
(m, c) => (this.is(m) ? t.success(m) : t.failure(m, c)),
59-
t.identity
60-
)
61-
}
62-
}
48+
const isString = (u: unknown): u is string => typeof u === 'string'
6349

64-
// codec instance: use this when building other codecs instances
65-
export const string = new StringType()
50+
const string = new t.Type<string, string, unknown>(
51+
'string',
52+
isString,
53+
(u, c) => (isString(u) ? t.success(u) : t.failure(u, c)),
54+
t.identity
55+
)
6656
```
6757

6858
A codec can be used to validate an object in memory (for example an API payload)
@@ -124,11 +114,14 @@ interface ContextEntry {
124114
readonly key: string
125115
readonly type: Decoder<any, any>
126116
}
117+
127118
interface Context extends ReadonlyArray<ContextEntry> {}
119+
128120
interface ValidationError {
129-
readonly value: mixed
121+
readonly value: unknown
130122
readonly context: Context
131123
}
124+
132125
interface Errors extends Array<ValidationError> {}
133126
```
134127

@@ -212,49 +205,47 @@ type Person = {
212205
import * as t from 'io-ts'
213206
```
214207

215-
| Type | TypeScript | codec / combinator |
216-
| ------------------------- | --------------------------------------- | ----------------------------------------------------- |
217-
| null | `null` | `t.null` or `t.nullType` |
218-
| undefined | `undefined` | `t.undefined` |
219-
| void | `void` | `t.void` or `t.voidType` |
220-
| string | `string` | `t.string` |
221-
| number | `number` | `t.number` |
222-
| boolean | `boolean` | `t.boolean` |
223-
| any | `any` | `t.any` |
224-
| never | `never` | `t.never` |
225-
| object | `object` | `t.object` |
226-
| integer || `t.Integer` |
227-
| array of any | `Array<mixed>` | `t.Array` |
228-
| array of type | `Array<A>` | `t.array(A)` |
229-
| dictionary of any | `{ [key: string]: mixed }` | `t.Dictionary` |
230-
| dictionary of type | `{ [K in A]: B }` | `t.dictionary(A, B)` |
231-
| function | `Function` | `t.Function` |
232-
| literal | `'s'` | `t.literal('s')` |
233-
| partial | `Partial<{ name: string }>` | `t.partial({ name: t.string })` |
234-
| readonly | `Readonly<T>` | `t.readonly(T)` |
235-
| readonly array | `ReadonlyArray<number>` | `t.readonlyArray(t.number)` |
236-
| type alias | `type A = { name: string }` | `t.type({ name: t.string })` |
237-
| tuple | `[ A, B ]` | `t.tuple([ A, B ])` |
238-
| union | `A \| B` | `t.union([ A, B ])` or `t.taggedUnion(tag, [ A, B ])` |
239-
| intersection | `A & B` | `t.intersection([ A, B ])` |
240-
| keyof | `keyof M` | `t.keyof(M)` |
241-
| recursive types | see [Recursive types](#recursive-types) | `t.recursion(name, definition)` |
242-
| refinement || `t.refinement(A, predicate)` |
243-
| exact types || `t.exact(type)` |
244-
| strict types (deprecated) || `t.strict({ name: t.string })` |
208+
| Type | TypeScript | codec / combinator |
209+
| ----------------- | --------------------------------------- | ----------------------------------------------------- |
210+
| null | `null` | `t.null` or `t.nullType` |
211+
| undefined | `undefined` | `t.undefined` |
212+
| void | `void` | `t.void` or `t.voidType` |
213+
| string | `string` | `t.string` |
214+
| number | `number` | `t.number` |
215+
| boolean | `boolean` | `t.boolean` |
216+
| unknown | `unknown` | t.unknown |
217+
| never | `never` | `t.never` |
218+
| object | `object` | `t.object` |
219+
| integer || `t.Integer` |
220+
| array of unknown | `Array<unknown>` | `t.UnknownArray` |
221+
| array of type | `Array<A>` | `t.array(A)` |
222+
| record of unknown | `Record<string, unknown>` | `t.UnknownRecord` |
223+
| record of type | `Record<K, A>` | `t.record(K, A)` |
224+
| function | `Function` | `t.Function` |
225+
| literal | `'s'` | `t.literal('s')` |
226+
| partial | `Partial<{ name: string }>` | `t.partial({ name: t.string })` |
227+
| readonly | `Readonly<T>` | `t.readonly(T)` |
228+
| readonly array | `ReadonlyArray<number>` | `t.readonlyArray(t.number)` |
229+
| type alias | `type A = { name: string }` | `t.type({ name: t.string })` |
230+
| tuple | `[ A, B ]` | `t.tuple([ A, B ])` |
231+
| union | `A \| B` | `t.union([ A, B ])` or `t.taggedUnion(tag, [ A, B ])` |
232+
| intersection | `A & B` | `t.intersection([ A, B ])` |
233+
| keyof | `keyof M` | `t.keyof(M)` |
234+
| recursive types | see [Recursive types](#recursive-types) | `t.recursion(name, definition)` |
235+
| refinement || `t.refinement(A, predicate)` |
236+
| exact types || `t.exact(type)` |
245237

246238
# Recursive types
247239

248240
Recursive types can't be inferred by TypeScript so you must provide the static type as a hint
249241

250242
```ts
251-
// helper type
252-
interface ICategory {
243+
interface Category {
253244
name: string
254-
categories: Array<ICategory>
245+
categories: Array<Category>
255246
}
256247

257-
const Category = t.recursion<ICategory>('Category', Category =>
248+
const Category: t.RecursiveType<t.Type<Category>> = t.recursion('Category', () =>
258249
t.type({
259250
name: t.string,
260251
categories: t.array(Category)
@@ -265,24 +256,24 @@ const Category = t.recursion<ICategory>('Category', Category =>
265256
## Mutually recursive types
266257

267258
```ts
268-
interface IFoo {
259+
interface Foo {
269260
type: 'Foo'
270-
b: IBar | undefined
261+
b: Bar | undefined
271262
}
272263

273-
interface IBar {
264+
interface Bar {
274265
type: 'Bar'
275-
a: IFoo | undefined
266+
a: Foo | undefined
276267
}
277268

278-
const Foo: t.RecursiveType<t.Type<IFoo>, IFoo> = t.recursion<IFoo>('Foo', _ =>
269+
const Foo: t.RecursiveType<t.Type<Foo>> = t.recursion('Foo', () =>
279270
t.interface({
280271
type: t.literal('Foo'),
281272
b: t.union([Bar, t.undefined])
282273
})
283274
)
284275

285-
const Bar: t.RecursiveType<t.Type<IBar>, IBar> = t.recursion<IBar>('Bar', _ =>
276+
const Bar: t.RecursiveType<t.Type<Bar>> = t.recursion('Bar', () =>
286277
t.interface({
287278
type: t.literal('Bar'),
288279
a: t.union([Foo, t.undefined])
@@ -450,6 +441,8 @@ Would be:
450441

451442
```ts
452443
import * as t from 'io-ts'
444+
445+
// t.Mixed = t.Type<any, any, unknown>
453446
const ResponseBody = <RT extends t.Mixed>(type: RT) =>
454447
t.interface({
455448
result: type,

dtslint/index.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,16 @@ type Type3TypeTest = Equals<t.TypeOf<typeof Type3>, { a: number }> // $ExpectTyp
107107
type Type3OutputTest = Equals<t.OutputOf<typeof Type3>, { a: string }> // $ExpectType "T"
108108

109109
//
110-
// dictionary
110+
// record
111111
//
112112

113-
const Dictionary1 = t.dictionary(t.keyof({ a: true }), t.number) // $ExpectType RecordC<KeyofC<{ a: boolean; }>, NumberC>
114-
type Dictionary1TypeTest = Equals<t.TypeOf<typeof Dictionary1>, { [K in 'a']: number }> // $ExpectType "T"
115-
type Dictionary1OutputTest = Equals<t.OutputOf<typeof Dictionary1>, { [K in 'a']: number }> // $ExpectType "T"
113+
const Record1 = t.record(t.keyof({ a: true }), t.number) // $ExpectType RecordC<KeyofC<{ a: boolean; }>, NumberC>
114+
type Record1TypeTest = Equals<t.TypeOf<typeof Record1>, { [K in 'a']: number }> // $ExpectType "T"
115+
type Record1OutputTest = Equals<t.OutputOf<typeof Record1>, { [K in 'a']: number }> // $ExpectType "T"
116116

117-
const Dictionary2 = t.dictionary(t.string, NumberFromString) // $ExpectType RecordC<StringC, Type<number, string, unknown>>
118-
type Dictionary2TypeTest = Equals<t.TypeOf<typeof Dictionary2>, { [K in string]: number }> // $ExpectType "T"
119-
type Dictionary2OutputTest = Equals<t.OutputOf<typeof Dictionary2>, { [K in string]: string }> // $ExpectType "T"
117+
const Record2 = t.record(t.string, NumberFromString) // $ExpectType RecordC<StringC, Type<number, string, unknown>>
118+
type Record2TypeTest = Equals<t.TypeOf<typeof Record2>, { [K in string]: number }> // $ExpectType "T"
119+
type Record2OutputTest = Equals<t.OutputOf<typeof Record2>, { [K in string]: string }> // $ExpectType "T"
120120

121121
//
122122
// union
@@ -413,7 +413,7 @@ interface GenerableProps {
413413
type GenerableInterface = t.InterfaceType<GenerableProps>
414414
type GenerableStrict = t.StrictType<GenerableProps>
415415
type GenerablePartials = t.PartialType<GenerableProps>
416-
interface GenerableDictionary extends t.DictionaryType<Generable, Generable> {}
416+
interface GenerableRecord extends t.DictionaryType<Generable, Generable> {}
417417
interface GenerableRefinement extends t.RefinementType<Generable> {}
418418
interface GenerableArray extends t.ArrayType<Generable> {}
419419
interface GenerableUnion extends t.UnionType<Array<Generable>> {}
@@ -431,7 +431,7 @@ type Generable =
431431
| GenerableArray
432432
| GenerableStrict
433433
| GenerablePartials
434-
| GenerableDictionary
434+
| GenerableRecord
435435
| GenerableUnion
436436
| GenerableIntersection
437437
| GenerableTuple

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "io-ts",
3-
"version": "1.7.0",
3+
"version": "1.7.1",
44
"description": "TypeScript compatible runtime type system for IO validation",
55
"files": [
66
"lib"

0 commit comments

Comments
 (0)