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.
const a = [1, 2, 3] as const;
let arr = a.map(r => r + '') // string[]
const a = [1, 2, 3] as const;
let arr = a.map(r => r + '') // [string, string, string]
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!
}
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
}
let o = Object.create({}) // any
let o = Object.create({}) // object
let t = Object.assign({ a: 7, b: 8 }, { b: '' }) // {a: number, b: never}
let t = Object.assign({ a: 7, b: 8 }, { b: '' }) // {a: number, b: string}
const a = { a: 1 }
const r = Object.defineProperty(a, "b", { value: 1, }); // {a: number}
const a = { a: 1 }
const r = Object.defineProperty(a, "b", { value: 1, }); // {a: number, readonly b: number}
const a = { a: 1 }
const rs = Object.defineProperties({ a: 1 }, { // {a: number}
b: { value: 1 }
});
const a = { a: 1 }
const rs = Object.defineProperties({ a: 1 }, { // {a: number, readonly b: number}
b: { value: 1 }
});
A very strong temptation was to make an Object.keys(obj)
returned (keys of obj)[]
instead of string[]
. However, in the process it was found out that such use is safe only if the received keys are used exclusively for comparison with primitives. But using them again as object type keys can lead to non-obvious errors at runtime (see for example, which will cause a runtime error). Thus, the usual redefinition of the type makes it less secure, and therefore we have abandoned such redefinition in this package. However, if you are determined, there is a safe way for you to do this using the ts-keys-turn package
type O = { a: number, b: number }
const obj: O = { a: 1, b: 1 }
const keys = Object.keys(obj) // string[]
const keys = Object.keys<O>(obj) // ("a" | "b")[]
However, this approach has several constraints (see the documentation)
Look up the section on configuring the package for use with Object.keys
There is also an unsafe branch that contains the aforementioned Object.keys
declaration, which assumes its use without any transformations, if you are willing to take responsibility for its use as keys
const keys = Object.keys<O>({a: 1, b: 1}) // ("a" | "b")[]
Improves detecting Element type from selector signature.
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
}
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
}
Original querySelector
required just to use generic to specify returned type that may differ from the runtime:
const misspell = document.querySelector<HTMLInputElement>('a.cls'); // is HTMLInputElement | null
if (misspell){
const replaced = misspell.value.replace('.', ',') // runtime error!
}
const misspell = document.querySelector('a.cls'); // is HTMLInputElement | null
if (misspell){
const replaced = misspell.value.replace('.', ',') // typescript error!
}
Now HTMLElement.cloneNode
allways returns HTMLElement
:
const elem = document.getElementById('id') // elem is HTMLElement
const clonedElem = elem?.cloneNode() // clonedElem is Node
const elem = document.getElementById('id') // elem is HTMLElement
const clonedElem = elem?.cloneNode() // clonedElem is HTMLElement also
Improved automatic type detection for the currentTarget
in MouseEvent
, KeyboardEvent
and other user interface events (only inside addEventListener
callback):
let elem: HTMLDivElement = document.querySelector('div');
elem?.addEventListener('click', e => {
let target = e.currentTarget; // is EventTarget | null
})
let elem: HTMLDivElement = document.querySelector('div');
elem?.addEventListener('click', e => {
let target = e.currentTarget; // is HTMLDivElement | null
})
Look up README.md
inside corresponding declaration directory.
npm i -D types-spring
add types-spring to include
list inside tsconfig.json
:
{
// ...,
"include": [
"./node_modules/**/*"
]
}
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 two useful improvements for Array.indexOf
and 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.
Despite the small contribution of ts-reset, I was very tempted to use some of its functions in types-spring, but I deliberately did not do it 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
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.
types-spring
and types-fest
may well complement each other. Of course, that's so
MIT