在一些情况下(如小项目等),我更喜欢用 Javascript ,同时也不介意使用 Typescript, 特别在一些较大的项目,特别是在使用 Svelte 进行表单验证的时候。 在使用 Svelte 不涉及表单验证等复杂场景的时候, 直接使用 Javascript 和 JSDoc 也可以获得不错的类型提示体验也很方便。 但在更复杂的场景如使用SuperformsZod 进行表单验证的时候, Typescript 会有更友好的编码体验(类型提示和类型检查)。

JsDoc类型注释

类型注释和使用可以在同一个文件,如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/**
 * @typedef Invoice
 * @type {Object}
 * @property {string} invoice
 * @property {string} paymentStatus
 * @property {string} totalAmount
 * @property {string} paymentMethod - payment method
 */

/** @type {Array<Invoice>} */
export const invoices = [
    {
        invoice: "INV001",
        paymentStatus: "Paid",
        totalAmount: "$250.00",
        paymentMethod: "Credit Card"
    }
]

也可以在跨文件共享使用类型注释:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// file: types.js
/**
 * @typedef Invoice
 * @type {Object}
 * @property {string} invoice
 * @property {string} paymentStatus
 * @property {string} totalAmount
 * @property {string} paymentMethod - payment method
 */

// file: invoice.js
/** @type { import('./types.js').Invoice[] } */
export const invoices = [
  {
    invoice: "INV001",
    paymentStatus: "Paid",
    totalAmount: "$250.00",
    paymentMethod: "Credit Card",
  },
];

Svelte 使用 TypeScript

在 Svelte components、Props、Slots、Events、Bindings 时,使用 Typescript 只需要将 lang="ts 添加到 script 标签:

  • components
1
2
3
4
5
6
7
<script lang="ts">
	let name: string = 'world';

	function greet(name: string) {
		alert(`Hello, ${name}!`);
	}
</script>
  • Props
1
2
3
<script lang="ts">
	export let name: string;
</script>
  • Slots
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<script lang="ts">
	export let name: string;
</script>

<slot {name} />

<!-- Later -->
<Comp let:name>
	<!--    ^ Inferred as string -->
	{name}
</Comp>
  • Events
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<script lang="ts">
	import { createEventDispatcher } from 'svelte';

	const dispatch = createEventDispatcher<{
		event: null; // does not accept a payload
		click: string; // has a required string payload
		type: string | null; // has an optional string payload
	}>();

	function handleClick() {
		dispatch('event');
		dispatch('click', 'hello');
	}

	function handleType() {
		dispatch('event');
		dispatch('type', Math.random() > 0.5 ? 'world' : null);
	}
</script>

<button on:click={handleClick} on:keydown={handleType}>Click</button>

Svelte 和 Zod

使用 zod validation library 时使用 Typescript 会更方便:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const accountSchema = z.object({
    name: z
        .string({ required_error: 'Required.' })
        .min(2, 'Name must be at least 2 characters.')
        .max(30, 'Name must not be longer than 30 characters.'),
    language: z.enum(languages.map(lang => lang.value) as [Language, ...Language[]]),
    dob: z
        .string()
        .datetime()
        .optional()
        .refine((date) => (date === undefined ? false : true), 'Please select a valid date.')
});

type AccountSchema = typeof accountSchema

此时如果不是在.ts文件使用zod, 而是有JSDoc注释 的常规.js文件,可以使用下面的方式,在JSDoc 中推断Zod类型:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
export const _formSchema = z.object({
    username: z.string().min(2, '最少两个字符').max(50, '最多50个字符'),
    email: z.string().email('无效邮箱地址'),
    bio: z.string().min(4).max(160).default("I own a computer."),
    urls: z
        .array(z.string().url())
        .default(["https://shadcn.com", "https://twitter.com/shadcn"]),
})

// Extract the inferred type as a JSDoc type
/** @typedef { z.infer<typeof _formSchema>} _form  */

参考