diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/expected.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/expected.json new file mode 100644 index 000000000..69651292d --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/expected.json @@ -0,0 +1,112 @@ +[ + { + "range": { + "start": { "line": 12, "character": 19 }, + "end": { "line": 12, "character": 20 } + }, + "severity": 4, + "source": "ts", + "message": "Parameter 'e' implicitly has an 'any' type, but a better type may be inferred from usage.", + "code": 7044, + "tags": [] + }, + { + "range": { + "start": { "line": 21, "character": 19 }, + "end": { "line": 21, "character": 20 } + }, + "severity": 4, + "source": "ts", + "message": "Parameter 'e' implicitly has an 'any' type, but a better type may be inferred from usage.", + "code": 7044, + "tags": [] + }, + { + "range": { + "start": { "line": 11, "character": 5 }, + "end": { "line": 11, "character": 12 } + }, + "severity": 1, + "source": "ts", + "message": "Type '{ owntype: string; }' is not assignable to type 'HTMLProps'.\n Property 'owntype' does not exist on type 'HTMLProps'.", + "code": 2322, + "tags": [] + }, + { + "range": { + "start": { "line": 12, "character": 5 }, + "end": { "line": 12, "character": 16 } + }, + "severity": 1, + "source": "ts", + "message": "Type '{ onownclick: (e: any) => any; }' is not assignable to type 'HTMLProps'.\n Property 'onownclick' does not exist on type 'HTMLProps'. Did you mean 'onclick'?", + "code": 2322, + "tags": [] + }, + { + "range": { + "start": { "line": 19, "character": 5 }, + "end": { "line": 19, "character": 12 } + }, + "severity": 1, + "source": "ts", + "message": "Type '{ owntype: boolean; }' is not assignable to type 'HTMLProps'.\n Property 'owntype' does not exist on type 'HTMLProps'.", + "code": 2322, + "tags": [] + }, + { + "range": { + "start": { "line": 20, "character": 5 }, + "end": { "line": 20, "character": 19 } + }, + "severity": 1, + "source": "ts", + "message": "Type 'boolean' is not assignable to type 'string'.", + "code": 2322, + "tags": [] + }, + { + "range": { + "start": { "line": 21, "character": 5 }, + "end": { "line": 21, "character": 16 } + }, + "severity": 1, + "source": "ts", + "message": "Type '{ onownclick: (e: any) => any; }' is not assignable to type 'HTMLProps'.\n Property 'onownclick' does not exist on type 'HTMLProps'. Did you mean 'onclick'?", + "code": 2322, + "tags": [] + }, + { + "range": { + "start": { "line": 22, "character": 41 }, + "end": { "line": 22, "character": 46 } + }, + "severity": 1, + "source": "ts", + "message": "Property 'wrong' does not exist on type '{ foo: string; }'.", + "code": 2339, + "tags": [] + }, + { + "range": { + "start": { "line": 24, "character": 22 }, + "end": { "line": 24, "character": 31 } + }, + "severity": 1, + "source": "ts", + "message": "Type 'boolean' is not assignable to type 'string'.", + "code": 2322, + "tags": [] + }, + { + "range": { + "start": { "line": 25, "character": 22 }, + "end": { "line": 25, "character": 32 } + }, + "severity": 1, + "source": "ts", + "message": "Type '{ doesnexist: string; }' is not assignable to type '{ attribute?: string; }'.\n Property 'doesnexist' does not exist on type '{ attribute?: string; }'.", + "code": 2322, + "tags": [] + } +] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/expectedv2.json new file mode 100644 index 000000000..f2618e227 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/expectedv2.json @@ -0,0 +1,90 @@ +[ + { + "range": { + "start": { "line": 15, "character": 13 }, + "end": { "line": 15, "character": 22 } + }, + "severity": 1, + "source": "ts", + "message": "Type 'boolean' is not assignable to type 'string'.", + "code": 2322, + "tags": [] + }, + { + "range": { + "start": { "line": 16, "character": 13 }, + "end": { "line": 16, "character": 30 } + }, + "severity": 1, + "source": "ts", + "message": "Argument of type '{ doesnexist: string; }' is not assignable to parameter of type '{ attribute?: string; }'.\n Object literal may only specify known properties, and '\"doesnexist\"' does not exist in type '{ attribute?: string; }'.", + "code": 2345, + "tags": [] + }, + { + "range": { + "start": { "line": 19, "character": 5 }, + "end": { "line": 19, "character": 12 } + }, + "severity": 1, + "source": "ts", + "message": "Type 'boolean' is not assignable to type 'string'.", + "code": 2322, + "tags": [] + }, + { + "range": { + "start": { "line": 20, "character": 5 }, + "end": { "line": 20, "character": 19 } + }, + "severity": 1, + "source": "ts", + "message": "Type 'boolean' is not assignable to type 'string'.", + "code": 2322, + "tags": [] + }, + { + "range": { + "start": { "line": 21, "character": 34 }, + "end": { "line": 21, "character": 39 } + }, + "severity": 1, + "source": "ts", + "message": "Property 'wrong' does not exist on type '{ foo: string; }'.", + "code": 2339, + "tags": [] + }, + { + "range": { + "start": { "line": 22, "character": 41 }, + "end": { "line": 22, "character": 46 } + }, + "severity": 1, + "source": "ts", + "message": "Property 'wrong' does not exist on type '{ foo: string; }'.", + "code": 2339, + "tags": [] + }, + { + "range": { + "start": { "line": 24, "character": 22 }, + "end": { "line": 24, "character": 31 } + }, + "severity": 1, + "source": "ts", + "message": "Type 'boolean' is not assignable to type 'string'.", + "code": 2322, + "tags": [] + }, + { + "range": { + "start": { "line": 25, "character": 22 }, + "end": { "line": 25, "character": 39 } + }, + "severity": 1, + "source": "ts", + "message": "Argument of type '{ doesnexist: string; }' is not assignable to parameter of type '{ attribute?: string; }'.\n Object literal may only specify known properties, and '\"doesnexist\"' does not exist in type '{ attribute?: string; }'.", + "code": 2345, + "tags": [] + } +] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/input.svelte new file mode 100644 index 000000000..5e3441aff --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/input.svelte @@ -0,0 +1,26 @@ + + + +
+
e.detail.foo} /> + + + + + + +
+
e.detail.foo} /> + + + + + + +
+
+
e.detail.wrong} /> +
e.detail.wrong} /> + + + diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/svelte-ambient-typings.d.ts b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/svelte-ambient-typings.d.ts new file mode 100644 index 000000000..a56dece67 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/svelte-ambient-typings.d.ts @@ -0,0 +1,24 @@ +/* eslint-disable */ +declare namespace svelte.JSX { + interface HTMLAttributes { + owntypefromold?: string; + onownclickfromold?: (event: CustomEvent<{ foo: string }>) => void; + } + interface IntrinsicElements { + 'own-element-from-old': { + attribute?: string; + }; + } +} + +declare namespace svelteHTML { + interface HTMLAttributes { + owntype?: string; + 'on:ownclick'?: (event: CustomEvent<{ foo: string }>) => void; + } + interface IntrinsicElements { + 'own-element': { + attribute?: string; + }; + } +} diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/tsconfig.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/tsconfig.json new file mode 100644 index 000000000..6d3385d79 --- /dev/null +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + /** + This is actually not needed, but makes the tests faster + because TS does not look up other types. + */ + "types": ["svelte"] + } +} diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/element-attributes/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/element-attributes/expectedv2.json index f6c59f911..f2db9acfd 100644 --- a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/element-attributes/expectedv2.json +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/element-attributes/expectedv2.json @@ -3,7 +3,7 @@ "range": { "start": { "line": 9, "character": 5 }, "end": { "line": 9, "character": 19 } }, "severity": 1, "source": "ts", - "message": "Argument of type '{ \"this-is\": string; }' is not assignable to parameter of type 'HTMLAttributes<...> & EventsWithColon> & svelteHTML.HTMLAttributes<...>'.\n Object literal may only specify known properties, and '\"this-is\"' does not exist in type 'HTMLAttributes<...> & EventsWithColon> & svelteHTML.HTMLAttributes<...>'.", + "message": "Argument of type '{ \"this-is\": string; }' is not assignable to parameter of type 'HTMLProps<\"div\", HTMLAttributes>'.\n Object literal may only specify known properties, and '\"this-is\"' does not exist in type 'HTMLProps<\"div\", HTMLAttributes>'.", "code": 2345, "tags": [] }, @@ -11,7 +11,7 @@ "range": { "start": { "line": 10, "character": 6 }, "end": { "line": 10, "character": 9 } }, "severity": 1, "source": "ts", - "message": "Argument of type '{ bar: string; }' is not assignable to parameter of type 'HTMLAttributes<...> & EventsWithColon> & svelteHTML.HTMLAttributes<...>'.\n Object literal may only specify known properties, and 'bar' does not exist in type 'HTMLAttributes<...> & EventsWithColon> & svelteHTML.HTMLAttributes<...>'.", + "message": "Argument of type '{ bar: string; }' is not assignable to parameter of type 'HTMLProps<\"div\", HTMLAttributes>'.\n Object literal may only specify known properties, and 'bar' does not exist in type 'HTMLProps<\"div\", HTMLAttributes>'.", "code": 2345, "tags": [] } diff --git a/packages/svelte2tsx/svelte-jsx.d.ts b/packages/svelte2tsx/svelte-jsx.d.ts index 28ec8f3c4..bf275ea20 100644 --- a/packages/svelte2tsx/svelte-jsx.d.ts +++ b/packages/svelte2tsx/svelte-jsx.d.ts @@ -3,6 +3,9 @@ declare namespace svelteHTML { // Every namespace eligible for use needs to implement the following two functions + /** + * @internal do not use + */ function mapElementTag( tag: K ): ElementTagNameMap[K]; @@ -13,6 +16,9 @@ declare namespace svelteHTML { tag: any ): any; // needs to be any because used in context of + /** + * @internal do not use + */ function createElement( // "undefined | null" because of element: Key | undefined | null, attrs: Elements[Key] @@ -43,15 +49,223 @@ declare namespace svelteHTML { type TransitionEventHandler = svelte.JSX.TransitionEventHandler; type MessageEventHandler = svelte.JSX.MessageEventHandler; - // For backwards-compatibility, in case someone enhanced the typings from svelteHtml.HTMLAttributes + // For backwards-compatibility and ease-of-use, in case someone enhanced the typings from import('./svelte-html-do-not-use').HTMLAttributes/SVGAttributes // eslint-disable-next-line @typescript-eslint/no-empty-interface interface HTMLAttributes {} + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface SVGAttributes {} + /** + * @internal do not use + */ type EventsWithColon = {[Property in keyof T as Property extends `on${infer Key}` ? `on:${Key}` : Property]?: T[Property] } - type WithOldJsxTypings = {[Property in keyof T]?: T[Property] & EventsWithColon & HTMLAttributes } - - // no "extends svelte.JSX" because else we wouldn't get the references to the right interfaces - interface IntrinsicElements extends WithOldJsxTypings {} + /** + * @internal do not use + */ + type HTMLProps = + // This omit chain ensures that properties manually defined in the new transformation take precedence + // over those manually defined in the old, taking precendence over the defaults, to make sth like this possible + // https://github.com/sveltejs/language-tools/issues/1352#issuecomment-1248627516 + Omit< + Omit> & EventsWithColon, + keyof Override + > & Override; + /** + * @internal do not use + */ + type RemoveIndex = { + [ K in keyof T as string extends K ? never : K ] : T[K] + }; + + // the following type construct makes sure that we can use the new typings while maintaining backwards-compatibility in case someone enhanced the old typings + interface IntrinsicElements extends Omit, keyof RemoveIndex> { + a: HTMLProps<'a', HTMLAttributes>; + abbr: HTMLProps<'abbr', HTMLAttributes>; + address: HTMLProps<'address', HTMLAttributes>; + area: HTMLProps<'area', HTMLAttributes>; + article: HTMLProps<'article', HTMLAttributes>; + aside: HTMLProps<'aside', HTMLAttributes>; + audio: HTMLProps<'audio', HTMLAttributes>; + b: HTMLProps<'b', HTMLAttributes>; + base: HTMLProps<'base', HTMLAttributes>; + bdi: HTMLProps<'bdi', HTMLAttributes>; + bdo: HTMLProps<'bdo', HTMLAttributes>; + big: HTMLProps<'big', HTMLAttributes>; + blockquote: HTMLProps<'blockquote', HTMLAttributes>; + body: HTMLProps<'body', HTMLAttributes>; + br: HTMLProps<'br', HTMLAttributes>; + button: HTMLProps<'button', HTMLAttributes>; + canvas: HTMLProps<'canvas', HTMLAttributes>; + caption: HTMLProps<'caption', HTMLAttributes>; + cite: HTMLProps<'cite', HTMLAttributes>; + code: HTMLProps<'code', HTMLAttributes>; + col: HTMLProps<'col', HTMLAttributes>; + colgroup: HTMLProps<'colgroup', HTMLAttributes>; + data: HTMLProps<'data', HTMLAttributes>; + datalist: HTMLProps<'datalist', HTMLAttributes>; + dd: HTMLProps<'dd', HTMLAttributes>; + del: HTMLProps<'del', HTMLAttributes>; + details: HTMLProps<'details', HTMLAttributes>; + dfn: HTMLProps<'dfn', HTMLAttributes>; + dialog: HTMLProps<'dialog', HTMLAttributes>; + div: HTMLProps<'div', HTMLAttributes>; + dl: HTMLProps<'dl', HTMLAttributes>; + dt: HTMLProps<'dt', HTMLAttributes>; + em: HTMLProps<'em', HTMLAttributes>; + embed: HTMLProps<'embed', HTMLAttributes>; + fieldset: HTMLProps<'fieldset', HTMLAttributes>; + figcaption: HTMLProps<'figcaption', HTMLAttributes>; + figure: HTMLProps<'figure', HTMLAttributes>; + footer: HTMLProps<'footer', HTMLAttributes>; + form: HTMLProps<'form', HTMLAttributes>; + h1: HTMLProps<'h1', HTMLAttributes>; + h2: HTMLProps<'h2', HTMLAttributes>; + h3: HTMLProps<'h3', HTMLAttributes>; + h4: HTMLProps<'h4', HTMLAttributes>; + h5: HTMLProps<'h5', HTMLAttributes>; + h6: HTMLProps<'h6', HTMLAttributes>; + head: HTMLProps<'head', HTMLAttributes>; + header: HTMLProps<'header', HTMLAttributes>; + hgroup: HTMLProps<'hgroup', HTMLAttributes>; + hr: HTMLProps<'hr', HTMLAttributes>; + html: HTMLProps<'html', HTMLAttributes>; + i: HTMLProps<'i', HTMLAttributes>; + iframe: HTMLProps<'iframe', HTMLAttributes>; + img: HTMLProps<'img', HTMLAttributes>; + input: HTMLProps<'input', HTMLAttributes>; + ins: HTMLProps<'ins', HTMLAttributes>; + kbd: HTMLProps<'kbd', HTMLAttributes>; + keygen: HTMLProps<'keygen', HTMLAttributes>; + label: HTMLProps<'label', HTMLAttributes>; + legend: HTMLProps<'legend', HTMLAttributes>; + li: HTMLProps<'li', HTMLAttributes>; + link: HTMLProps<'link', HTMLAttributes>; + main: HTMLProps<'main', HTMLAttributes>; + map: HTMLProps<'map', HTMLAttributes>; + mark: HTMLProps<'mark', HTMLAttributes>; + menu: HTMLProps<'menu', HTMLAttributes>; + menuitem: HTMLProps<'menuitem', HTMLAttributes>; + meta: HTMLProps<'meta', HTMLAttributes>; + meter: HTMLProps<'meter', HTMLAttributes>; + nav: HTMLProps<'nav', HTMLAttributes>; + noscript: HTMLProps<'noscript', HTMLAttributes>; + object: HTMLProps<'object', HTMLAttributes>; + ol: HTMLProps<'ol', HTMLAttributes>; + optgroup: HTMLProps<'optgroup', HTMLAttributes>; + option: HTMLProps<'option', HTMLAttributes>; + output: HTMLProps<'output', HTMLAttributes>; + p: HTMLProps<'p', HTMLAttributes>; + param: HTMLProps<'param', HTMLAttributes>; + picture: HTMLProps<'picture', HTMLAttributes>; + pre: HTMLProps<'pre', HTMLAttributes>; + progress: HTMLProps<'progress', HTMLAttributes>; + q: HTMLProps<'q', HTMLAttributes>; + rp: HTMLProps<'rp', HTMLAttributes>; + rt: HTMLProps<'rt', HTMLAttributes>; + ruby: HTMLProps<'ruby', HTMLAttributes>; + s: HTMLProps<'s', HTMLAttributes>; + samp: HTMLProps<'samp', HTMLAttributes>; + slot: HTMLProps<'slot', HTMLAttributes>; + script: HTMLProps<'script', HTMLAttributes>; + section: HTMLProps<'section', HTMLAttributes>; + select: HTMLProps<'select', HTMLAttributes>; + small: HTMLProps<'small', HTMLAttributes>; + source: HTMLProps<'source', HTMLAttributes>; + span: HTMLProps<'span', HTMLAttributes>; + strong: HTMLProps<'strong', HTMLAttributes>; + style: HTMLProps<'style', HTMLAttributes>; + sub: HTMLProps<'sub', HTMLAttributes>; + summary: HTMLProps<'summary', HTMLAttributes>; + sup: HTMLProps<'sup', HTMLAttributes>; + table: HTMLProps<'table', HTMLAttributes>; + template: HTMLProps<'template', HTMLAttributes>; + tbody: HTMLProps<'tbody', HTMLAttributes>; + td: HTMLProps<'td', HTMLAttributes>; + textarea: HTMLProps<'textarea', HTMLAttributes>; + tfoot: HTMLProps<'tfoot', HTMLAttributes>; + th: HTMLProps<'th', HTMLAttributes>; + thead: HTMLProps<'thead', HTMLAttributes>; + time: HTMLProps<'time', HTMLAttributes>; + title: HTMLProps<'title', HTMLAttributes>; + tr: HTMLProps<'tr', HTMLAttributes>; + track: HTMLProps<'track', HTMLAttributes>; + u: HTMLProps<'u', HTMLAttributes>; + ul: HTMLProps<'ul', HTMLAttributes>; + var: HTMLProps<'var', HTMLAttributes>; + video: HTMLProps<'video', HTMLAttributes>; + wbr: HTMLProps<'wbr', HTMLAttributes>; + webview: HTMLProps<'webview', HTMLAttributes>; + // SVG + svg: HTMLProps<'svg', SVGAttributes>; + + animate: HTMLProps<'animate', SVGAttributes>; + animateMotion: HTMLProps<'animateMotion', SVGAttributes>; + animateTransform: HTMLProps<'animateTransform', SVGAttributes>; + circle: HTMLProps<'circle', SVGAttributes>; + clipPath: HTMLProps<'clipPath', SVGAttributes>; + defs: HTMLProps<'defs', SVGAttributes>; + desc: HTMLProps<'desc', SVGAttributes>; + ellipse: HTMLProps<'ellipse', SVGAttributes>; + feBlend: HTMLProps<'feBlend', SVGAttributes>; + feColorMatrix: HTMLProps<'feColorMatrix', SVGAttributes>; + feComponentTransfer: HTMLProps<'feComponentTransfer', SVGAttributes>; + feComposite: HTMLProps<'feComposite', SVGAttributes>; + feConvolveMatrix: HTMLProps<'feConvolveMatrix', SVGAttributes>; + feDiffuseLighting: HTMLProps<'feDiffuseLighting', SVGAttributes>; + feDisplacementMap: HTMLProps<'feDisplacementMap', SVGAttributes>; + feDistantLight: HTMLProps<'feDistantLight', SVGAttributes>; + feDropShadow: HTMLProps<'feDropShadow', SVGAttributes>; + feFlood: HTMLProps<'feFlood', SVGAttributes>; + feFuncA: HTMLProps<'feFuncA', SVGAttributes>; + feFuncB: HTMLProps<'feFuncB', SVGAttributes>; + feFuncG: HTMLProps<'feFuncG', SVGAttributes>; + feFuncR: HTMLProps<'feFuncR', SVGAttributes>; + feGaussianBlur: HTMLProps<'feGaussianBlur', SVGAttributes>; + feImage: HTMLProps<'feImage', SVGAttributes>; + feMerge: HTMLProps<'feMerge', SVGAttributes>; + feMergeNode: HTMLProps<'feMergeNode', SVGAttributes>; + feMorphology: HTMLProps<'feMorphology', SVGAttributes>; + feOffset: HTMLProps<'feOffset', SVGAttributes>; + fePointLight: HTMLProps<'fePointLight', SVGAttributes>; + feSpecularLighting: HTMLProps<'feSpecularLighting', SVGAttributes>; + feSpotLight: HTMLProps<'feSpotLight', SVGAttributes>; + feTile: HTMLProps<'feTile', SVGAttributes>; + feTurbulence: HTMLProps<'feTurbulence', SVGAttributes>; + filter: HTMLProps<'filter', SVGAttributes>; + foreignObject: HTMLProps<'foreignObject', SVGAttributes>; + g: HTMLProps<'g', SVGAttributes>; + image: HTMLProps<'image', SVGAttributes>; + line: HTMLProps<'line', SVGAttributes>; + linearGradient: HTMLProps<'linearGradient', SVGAttributes>; + marker: HTMLProps<'marker', SVGAttributes>; + mask: HTMLProps<'mask', SVGAttributes>; + metadata: HTMLProps<'metadata', SVGAttributes>; + mpath: HTMLProps<'mpath', SVGAttributes>; + path: HTMLProps<'path', SVGAttributes>; + pattern: HTMLProps<'pattern', SVGAttributes>; + polygon: HTMLProps<'polygon', SVGAttributes>; + polyline: HTMLProps<'polyline', SVGAttributes>; + radialGradient: HTMLProps<'radialGradient', SVGAttributes>; + rect: HTMLProps<'rect', SVGAttributes>; + stop: HTMLProps<'stop', SVGAttributes>; + switch: HTMLProps<'switch', SVGAttributes>; + symbol: HTMLProps<'symbol', SVGAttributes>; + text: HTMLProps<'text', SVGAttributes>; + textPath: HTMLProps<'textPath', SVGAttributes>; + tspan: HTMLProps<'tspan', SVGAttributes>; + use: HTMLProps<'use', SVGAttributes>; + view: HTMLProps<'view', SVGAttributes>; + + // Svelte specific + 'svelte:window': HTMLProps<'svelte:window', HTMLAttributes>; + 'svelte:body': HTMLProps<'svelte:body', HTMLAttributes>; + 'svelte:fragment': { slot?: string }; + 'svelte:options': { [name: string]: any }; + 'svelte:head': { [name: string]: any }; + + [name: string]: { [name: string]: any }; + } + } /**