Skip to content

Instantly share code, notes, and snippets.

@Kcko
Last active March 3, 2025 10:12
Show Gist options
  • Save Kcko/1f7afa4ef1cdf83a284248656decacd2 to your computer and use it in GitHub Desktop.
Save Kcko/1f7afa4ef1cdf83a284248656decacd2 to your computer and use it in GitHub Desktop.
<!-- 1. PROPS -->
<!-- JS -->
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
foo: { type: String, required: true },
bar: Number,
});
// props.foo is a string
// props.bar is a number or undefined
</script>
<!-- TS -->
<script setup lang="ts">
const props = defineProps<{
foo: string;
bar?: number;
}>()
</script>
<script setup lang="ts">
interface Props {
foo: string;
bar?: number;
}
const props = defineProps<Props>()
</script>
<!-- 2. EMITS -->
<!-- JS -->
<script setup>
const emit = defineEmits(['change', 'update'])
</script>
<!-- TS -->
<script setup lang="ts">
const emit = defineEmits<{
change: [id: number]
update: [value: string]
}>()
</script>
<!-- 3. Typing Ref and Reactive Data => Inference -->
<script setup>
import { ref } from 'vue';
const count = ref(0);
count.value = 'string'; // error, inference, we expect number
</script>
<!-- 4. Typing Server Responses -->
<script setup lang="ts">
import { ref, onMounted } from 'vue';
interface User {
id: number;
name: string;
email: string;
}
const userData = ref<User | null>(null);
onMounted(async () => {
const response = await fetch('https://api.example.com/user');
const data: User = await response.json();
userData.value = data; // TypeScript ensures data usages match the User interface
});
</script>
<!-- 5. Typing Computed Data -->
import { ref, computed } from 'vue'
const count = ref(0)
// inferred type: ComputedRef<number>
const double = computed(() => count.value * 2)
// => TS Error: Property 'split' does not exist on type 'number'
const result = double.value.split('')
// or explicitely define return type
const double = computed<number>(() => {
// type error if this doesn't return a number
})
<!-- 6. Typing Scoped Slots-->
<template>
<slot :msg="message"></slot>
</template>
<script setup lang="ts">
const message = 'Hello, Vue!';
const slots = defineSlots<{
default: (props: { msg: string }) => any;
}>()
</script>
<!-- 7. Typing Template Refs -->
<script setup lang="ts">
import { useTemplateRef, onMounted } from 'vue';
const myInput = useTemplateRef('my-input');
onMounted(() => {
myInput.value?.focus();
});
</script>
<template>
<input ref="my-input" />
</template>
<!-- 8. Typing Provide/Inject -->
<!-- ParentComponent.vue -->
<script setup lang="ts">
import { provide } from 'vue';
const theme = 'dark';
provide('theme', theme);
</script>
<!-- ChildComponent.vue -->
<script setup lang="ts">
import { inject } from 'vue';
const theme = inject<string>('theme'); // Inject with expected type
// TypeScript ensures that 'theme' is of type string
</script>
<!-- 9. Generics -->
<script setup lang="ts" generic="T">
defineProps<{
items: T[]; // Array of items of type T
selected: T; // Single selected item of type T
}>()
</script>
<!-- 10. Typed Composables -->
// useUser.ts
import { ref } from 'vue';
interface User {
id: number;
name: string;
age: number;
}
export function useUser() {
const user = ref<User | null>(null);
function fetchUser(id: number) {
// Fetching user logic
user.value = { id, name: 'John Doe', age: 30 };
}
return { user, fetchUser };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment