Skip to content

improved types for every day sounding like symphony

License

Notifications You must be signed in to change notification settings

Sanshain/types-spring

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

91 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

types-spring (unsafe branch)

unsafe branch

npm npm

A package that aims to eliminate some of the shortcomings of the built-in types in standard ts libraries and deliver additional utility types that will facilitate daily work. Inspired by ts-reset.

Built-in types features:

Array.map

before:

const a = [1, 2, 3] as const;
let arr = a.map(r => r + '')                              // string[]

after:

const a = [1, 2, 3] as const;
let arr = a.map(r => r + '')                             // [string, string, string]

Array.isArray

before:

function checkArray(a: { a: 1 } | ReadonlyArray<number>) 
{
    if (Array.isArray(a)) {                              
        a.forEach(item => item.f())                         // => runtime error!
    }
    else { a.a }                                            // type error: property `a` does not exists!
}

after:

function checkArray(a: { a: 1 } | ReadonlyArray<number>) 
{
    if (Array.isArray(a)) {
        a.forEach(item => item.f())                         // type error: f does not exist on type number
    }
    else { a.a }                                            // success 
}

Object.assign

before:

let t = Object.assign({ a: 7, b: 8 }, { b: '' })            // {a: number, b: never}

after:

let t = Object.assign({ a: 7, b: 8 }, { b: '' })            // {a: number, b: string}

Object.defineProperty

before:

const a = { a: 1 }
const r = Object.defineProperty(a, "b", { value: 1, });     // {a: number}

after:

const a = { a: 1 }
const r = Object.defineProperty(a, "b", { value: 1, });     // {a: number, readonly b: number}

Object.defineProperties

before:

const a = { a: 1 }
const rs = Object.defineProperties({ a: 1 }, {              // {a: number}
    b: { value: 1 }
});

after:

const a = { a: 1 }
const rs = Object.defineProperties({ a: 1 }, {              // {a: number, readonly b: number}
    b: { value: 1 }
});

Object.keys

before:

type O = { a: number, b: number }
const obj: O = { a: 1, b: 1 }

const keys = Object.keys(obj)                    // string[]
const entries = Object.entries(obj)              // [string, number][]

after:

type O = { a: number, b: number }
const obj: O = { a: 1, b: 1 }

const keys = Object.keys<O>({a: 1, b: 1})        // ("a" | "b")[]

Important: use the overridden signature with generic only if you plan to use the received keys exclusively for comparison with primitives - such use is type-safe. However, if you decide to use them again as keys, know that with a careless approach, you can get a runtime errors like caused by this

DOM features:

querySelector

Improves detecting Element type from selector signature.

before:

const input = document.querySelector('input');                         // is HTMLInputElement | null
const unknown = document.querySelector('.cls');                        // is Element | null
const inputWCls = document.querySelector('input.cls');                 // is Element | null

if (divCls) {
    inputWCls.value = ''                                               // error
}

after:

const input = document.querySelector('input');                      // is HTMLInputElement | null
const unknown = document.querySelector('.cls');                     // is Element | null
const inputWCls = document.querySelector('input.cls');              // is HTMLInputElement | null
if (divCls) {
    inputWCls.value = ''                                            // success
}

querySelector<Type>

Original querySelector required just to use generic to specify returned type that may differ from the runtime:

before:

const misspell = document.querySelector<HTMLInputElement>('a.cls');         // is HTMLInputElement | null
if (misspell){
    const replaced = misspell.value.replace('.', ',')                       // runtime error!
}

after:

const misspell = document.querySelector('a.cls');                           // is HTMLInputElement | null
if (misspell){
    const replaced = misspell.value.replace('.', ',')                       // typescript error!
}

cloneNode

Now HTMLElement.cloneNode allways returns HTMLElement:

before:

const elem = document.getElementById('id')              // elem is HTMLElement
const clonedElem = elem?.cloneNode()                    // clonedElem is Node

after:

const elem = document.getElementById('id')              // elem is HTMLElement
const clonedElem = elem?.cloneNode()                    // clonedElem is HTMLElement also

currentTarget

Improved automatic type detection for the currentTarget in MouseEvent, KeyboardEvent and other user interface events:

before:

let elem: HTMLDivElement = document.querySelector('div');
elem?.addEventListener('click', e => {        
    let target = e.currentTarget;                       // is EventTarget | null
})

after:

let elem: HTMLDivElement = document.querySelector('div');
elem?.addEventListener('click', e => {        
    let target = e.currentTarget;                       // is HTMLDivElement | null
})

Utility types:

Look up README.md inside corresponding declarations.

How to use

npm i -D Sanshain/types-spring#unsafe

To patch the built-in types:

add types-spring to include list inside tsconfig.json:

{
    // ...,
    "include": [
        "./node_modules/**/*"
    ]    
}

Similar packages:

ts-reset

As it was said at the beginning, this package was inspired by ts-reset. At first glance, it seemed that the ts-reset does very little: it just overrides in tslib any to unknown type wherever possible, and contains very limited number of improvements (like Array.filter). However despite the fact that in this one there are not so much features, it is very profound and I would say that the author is very scrupulous about safing.

Compatibility

Despite the modest ts-reset contribution to typescript world, I was tempted to use some of its features in types-spring, but I deliberately did not do that in order not to repeat what other people have already done in the best possible way before me. I consider ts-reset as be a fundamental package, and the best thing to do today is to use these two these packages (ts-reset and types-spring) together

types-fest

This is a awesome package with a huge number of utility types. When I started working on types-string, I didn't know anything about it. However, when I got awared, to my surprise found that most of them (with the exception of just two) do not overlap with types-spring! It turns out that these are completely different packages with different tools, since their authors think differently.

Compatibility

types-spring and types-fest may well complement each other. Of course, that's so

Licence

MIT

GitHub

About

improved types for every day sounding like symphony

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages