total-typescript / ts-reset

A 'CSS reset' for TypeScript, improving types for common JavaScript API's
https://www.totaltypescript.com/ts-reset
MIT License
7.74k stars 117 forks source link

Better typings for KeyboardEvent.key #143

Open iway1 opened 1 year ago

iway1 commented 1 year ago

KeyboardEvent.key is typed as a string, even though it's a union of string literals.

window.addEventListener('keydown', (e)=>{
  // string type
  e.key
})

Would be really nice to get autocomplete here =D

qb20nh commented 1 year ago

https://www.w3.org/TR/uievents-key/#keys-unicode

Almost every Unicode character can be used as a valid key attribute value, but there is a small set of Unicode characters which MUST NOT be used. We introduce the concept of a key string to identify the set of Unicode strings that are appropriate for use as a key attribute value.

A key string is a string containing a 0 or 1 non-control characters ("base" characters) followed by 0 or more combining characters. The string MUST be in Normalized Form C (NFC) as described in [UAX15].

A non-control character is any valid Unicode character except those that are part of the "Other, Control" ("Cc") General Category.

A combining character is any valid Unicode character in the "Mark, Spacing Combining" ("Mc") General Category or with a non-zero Combining Class.

Listing all possible value is possible but impractical considering all the keyboard configurations around the globe and ever changing Unicode standard. Quick good enough solution could be only including US keyboard keys plus predefined keys.

tommy-mitchell commented 6 months ago

Related: https://github.com/microsoft/TypeScript/issues/38886

qb20nh commented 6 months ago

Hack to make autocompletion work: https://github.com/microsoft/TypeScript/issues/29729#issuecomment-471566609

type LiteralUnion<T extends U, U = string> = T | (U & { zz_IGNORE_ME?: never })

type Color = LiteralUnion<'red' | 'black'>

var c: Color = 'red'                    // Has intellisense
var d: Color = 'any-string'             // Any string is OK
var d: Color = { zz_IGNORE_ME: '' }     // { zz_IGNORE_ME } placeholder is at the bottom of intellisense list and errors because of never 

type N = LiteralUnion<1 | 2, number> // Works with numbers too