jobs throughwww.vuejobs.com
This page assumes that you have already read the overviewUsing Vue with TypeScript.
Accessories for writing components#
Use<script setting>
#
if you use<script setting>
, DiedefineAccesorios()
The macro supports inferring accessory types based on its argument:
outlook
<Text setting language="t">ConstantlyAccesories= defineaccessories({ Foo: { writes:line, necessary: true }, Bar:number})Accesories.Foo// StringAccesories.Bar// number | not defined</Text>
This is called a "runtime declaration" because the argument passed todefineAccesorios()
is used as runtimeAccesories
Possibility.
However, it is often easier to define purely typed props via a generic type argument:
outlook
<Text setting language="t">ConstantlyAccesories= defineaccessories<{ Foo: line Bar?: number}>()</Text>
This is called a "type-based declaration". The compiler tries its best to infer the equivalent run-time options based on the type argument. In this case, our second example compiles exactly the same runtime options as the first example.
You can use either a type-based declaration OR a run-time declaration, but you cannot use both at the same time.
We can also move the accessory types to a separate interface:
outlook
<Text setting language="t">interface Accesories { Foo: line Bar?: number}ConstantlyAccesories= defineaccessories<Accesories>()</Text>
syntax restrictions#
To generate the correct runtime code, the generic argument todefineAccesorios()
must be one of the following:
A literal object type:
t
defineaccessories<{ /*... */ }>()
A reference to an interface or object type literalin the same file:
t
interface Accesories {/* ... */}defineaccessories<Accesories>()
The object or interface type literal may contain references to types imported from other files, but the generic argument itself was passeddefineaccessories
can notbe an imported type:
t
import { Accesories } since './other-file'// Unsupporteddefineaccessories<Accesories>()
This is because Vue components are compiled in isolation and the compiler does not currently crawl imported files to analyze the source type. This limitation may be removed in a future release.
Default settings for accessories#
If we use a type-based declaration, we lose the ability to declare default values for props. This can be solved by thewith default values
Compiler Macro:
t
export interface Accesories { message?: line hang tags?: line[]}ConstantlyAccesories= with default values(defineaccessories<Accesories>(), { message: 'Hallo', hang tags: () =>['a', 'Von']})
This is compiled into equivalent runtime propsLack
Options additionally thewith default values
helper provides type checks for default values and ensures that values are returnedAccesories
type removed the optional flags for properties that declared default values.
Alternatively, you can use the currently experimental onereactivity transformation:
outlook
<Text setting language="t">interface Accesories { Name: line tell?: number}// reactive structure for defineProps()// The default value is compiled into the appropriate runtime optionConstantly {Name,tell= 100 } = defineaccessories<Accesories>()</Text>
This behavior currently requiresexpress subscription.
sin<script setting>
#
Nobody<script setting>
, it is necessary to usedefinirComponente()
to allow conclusions about accessory types. The type of Props object to pass toSetting()
is derived from theAccesories
Possibility.
t
import { definirComponente } since 'outlook'export Lack definirComponente({ Accesories: { message:line }, setting(Accesories) { Accesories.message // <-- type: string }})
Write component issues#
In<script setting>
, Dieoutput
The function can also be written using the runtime declaration OR the type declaration:
outlook
<Text setting language="t">// execution timeConstantlyoutput= Define emissions(['change', 'To update'])// based on typesConstantlyoutput= Define emissions<{ (mi: 'change', I WOULD: number): file (mi: 'To update', bravery: line): file}>()</Text>
The type argument must be a type literal withcall signatures. The literal type is used as the return type.output
Function. As we can see, the type declaration gives us much finer control over the type constraints of the events emitted.
when not in use<script setting>
,definirComponente()
is able to derive the events allowed foroutput
Feature exposed in configuration context:
t
import { definirComponente } since 'outlook'export Lack definirComponente({ output:['change'], setting(Accesories, { output }) { output('change')// <-- Type checking / auto-completion }})
typewritingReferee()
#
References infer the type from the initial value:
t
import { referee } since 'outlook'// Derived type: Ref<number>ConstantlyYear= referee(2020)// => TS error: type 'string' cannot be mapped to type 'number'.Year.bravery= '2020'
Sometimes we may need to specify complex types for the intrinsic value of a reference. We can do that with thereferee
writes:
t
import { referee } since 'outlook'import writes { referee } since 'outlook'ConstantlyYear: referee<line | number> = referee('2020')Year.bravery= 2020 // OK!
Or by passing a generic argument when callingReferee()
to override the default inference:
t
// Result type: Ref<string | number>ConstantlyYear= referee<line | number>('2020')Year.bravery= 2020 // OK!
If you supply a generic type argument but omit the initial value, the resulting type is an enclosing union typeNot defined
:
t
// Derived type: Ref<number | undefined>ConstantlyNorte= referee<number>()
typewritingReagent()
#
Reagent()
it also implicitly infers the nature of its argument:
t
import { Reagent } since 'outlook'// derived type: {title: string}ConstantlyBook= Reagent({ title: 'See 3 guide' })
To explicitly write aReagent
property we can use interfaces:
t
import { Reagent } since 'outlook'interface Buch { title: line Year?: number}ConstantlyBook: Buch = Reagent({ title: 'See 3 guide' })
BRIBERY
It is not recommended to use the generic argument ofReagent()
since the return type, which handles unpacking of nested references, is different from the generic argument type.
typewritingcalculated()
#
calculated()
infers its type based on the return value of the getter:
t
import { referee, calculated } since 'outlook'Constantlytell= referee(0)// Derived type: ComputedRef<number>Constantlydouble= calculated(() =>tell.bravery* 2)// => TS error: property 'split' does not exist on type 'number'Constantlyresult=double.bravery.pull apart('')
You can also specify an explicit type via a generic argument:
t
Constantlydouble= calculated<number>(() => { // typo if this doesn't return a number})
Write event handlers#
When dealing with native DOM events, it can be helpful to properly spell the argument we're passing to the controller. Let's look at this example:
outlook
<Text setting language="t">function handleChange(event) { // `event` is implicitly of `any` type console.log in(event.Goal.bravery)}</Text><model> <Entry writes="Text"@change="handleChange"/></model>
Without type annotation, theevent
Argument implicitly has a type ofnone
. This will also result in a TS error if"strict": true
Ö"noImplicitAny": true
be used in ittsconfig.json
. Therefore, it is recommended to comment out the event handler argument explicitly. Also, you may need to explicitly cast the properties toevent
:
t
function handleChange(event: incident) { console.log in((event.Goal like HTMLInputElement).bravery)}
Enter Deploy/Inject#
Feeding and injecting usually take place in separate components. In order to correctly write the fed values, Vue provides ainjection key
Interface that is a generic type that is extendedSymbol
. It can be used to synchronize the type of value inserted between the provider and the consumer:
t
import { Offer, inject } since 'outlook'import writes { injection key } since 'outlook'Constantlykey= Symbol()like injection key<line>Offer(Key, 'Foo')// Specifying a non-string value will result in an errorConstantlyFoo= inject(Key)// type of foo: string | not defined
It is recommended to put the injection key in a separate file so that it can be imported into multiple components.
When using string injection keys, is the type of the injected valuea foreign
, and must be declared explicitly via a generic type argument:
t
ConstantlyFoo= inject<line>('Foo')// type: string | not defined
Note that the value fed in can still beNot defined
, since there is no guarantee that a provider will provide this value at runtime.
ThatNot defined
The type can be removed by providing a default value:
t
ConstantlyFoo= inject<line>('Foo', 'Bar')// type: string
If you are sure that the value will always be provided, you can also force the value to be converted:
t
ConstantlyFoo= inject('Foo')like line
Write template references#
Template references must be created with an explicit generic type argument and an initial value ofNull
:
outlook
<Text setting language="t">import { referee, in assembled condition } since 'outlook'ConstantlyDie= referee<HTMLInputElement | Null>(Null)in assembled condition(() => { Die.bravery?.Focus()})</Text><model> <Entry referee="Die"/></model>
Note that strong type safety requires using optional concatenation or type guards when accessingthe value
. This is because is the initial reference valueNull
until the component is assembled, and can also be adjustedNull
when the referenced element is unmounted byinsi
.
Write references to component templates#
Sometimes you may need to annotate a template reference for a child component to invoke its public method. For example, we have oneMiModal
child component with a method that opens the modal:
outlook
<!-- MiModal.view --><Text setting language="t">import { referee } since 'outlook'Constantlycontent is displayed= referee(NOT CORRECT)Constantlyopen= () =>(Content is displayed.bravery= true)definirExponer({open})</Text>
To get the instance type ofMiModal
, we need to get its type via firstSo'ne Art
, then use the built-in TypeScriptinstance type
Instance type extract utility:
outlook
<!-- app.vue --><Text setting language="t">importMiModalsince './MiModal.vue'Constantlymodal= referee<instance type< somehowMiModal> | Null>(Null)ConstantlyopenModal= () => { modal.bravery?.open()}</Text>
Note that if you want to use this technique for TypeScript files instead of Vue SFC, you need to enable Volaracquisition mode.