I want to know the | operator meaning, could anyone explain?
here's some short code snippet in src/core/vdom/vnode.js
export default class VNode {
tag: string | void;
data: VNodeData | void;
children: ?Array<VNode>;
text: string | void;
elm: Node | void;
ns: string | void;
context: Component | void; // rendered in this component's scope
functionalContext: Component | void; // only for functional component root nodes
key: string | number | void;
componentOptions: VNodeComponentOptions | void;
child: Component | void; // component instance
parent: VNode | void; // component placeholder node
raw: boolean; // contains raw HTML? (server only)
isStatic: boolean; // hoisted static node
isRootInsert: boolean; // necessary for enter transition check
isComment: boolean; // empty comment placeholder?
isCloned: boolean; // is a cloned node?
isOnce: boolean; // is a v-once node?
Here | is an OR unary operator.
ns: string | void;
which means ns is of type string, but if string is not defined due to some reason, it will be of type void. This should be just for precaution if it is not defined in some browser version.
Related
I'm trying to add angularfire database module to a new angular project but when i add the line :
import { AngularFireDatabaseModule } from '#angular/fire/compat/database';
i get this error :
Error: node_modules/#angular/fire/compat/database/interfaces.d.ts:47:18 - error TS2430: Interface 'DatabaseSnapshotExists<T>' incorrectly extends interface 'DataSnapshot'.
Types of property 'forEach' are incompatible.
Type '(action: (a: DatabaseSnapshot<T>) => boolean) => boolean' is not assignable to type '(action: (a: DataSnapshot & { key: string; }) => boolean | void) => boolean'.
Types of parameters 'action' and 'action' are incompatible.
Types of parameters 'a' and 'a' are incompatible.
Type 'DatabaseSnapshot<T>' is not assignable to type 'DataSnapshot & { key: string; }'.
Type 'DatabaseSnapshotExists<T>' is not assignable to type 'DataSnapshot & { key: string; }'.
Type 'DatabaseSnapshotExists<T>' is not assignable to type 'DataSnapshot'.
Types of property 'forEach' are incompatible.
Type '(action: (a: DatabaseSnapshot<T>) => boolean) => boolean' is not assignable to type '(action: (a: DataSnapshot & { key: string; }) => boolean | void) => boolean'.
Types of parameters 'action' and 'action' are incompatible.
Types of parameters 'a' and 'a' are incompatible.
Type 'DatabaseSnapshot<T>' is not assignable to type 'DataSnapshot & { key: string; }'.
Type 'DatabaseSnapshotDoesNotExist<T>' is not assignable to type 'DataSnapshot &
{ key: string; }'.
Type 'DatabaseSnapshotDoesNotExist<T>' is not assignable to type '{ key: string; }'.
Types of property 'key' are incompatible.
Type 'string | null' is not assignable to type 'string'.
Type 'null' is not assignable to type 'string'.
47 export interface DatabaseSnapshotExists<T> extends firebase.database.DataSnapshot {
~~~~~~~~~~~~~~~~~~~~~~
Error: node_modules/#angular/fire/compat/database/interfaces.d.ts:52:18 - error TS2430: Interface 'DatabaseSnapshotDoesNotExist<T>' incorrectly extends interface 'DataSnapshot'.
Types of property 'forEach' are incompatible.
Type '(action: (a: DatabaseSnapshot<T>) => boolean) => boolean' is not assignable to type '(action: (a: DataSnapshot & { key: string; }) => boolean | void) => boolean'.
Types of parameters 'action' and 'action' are incompatible.
Types of parameters 'a' and 'a' are incompatible.
Type 'DatabaseSnapshot<T>' is not assignable to type 'DataSnapshot & { key: string; }'.
Type 'DatabaseSnapshotDoesNotExist<T>' is not assignable to type 'DataSnapshot & { key: string; }'.
Type 'DatabaseSnapshotDoesNotExist<T>' is not assignable to type 'DataSnapshot'.
Types of property 'forEach' are incompatible.
Type '(action: (a: DatabaseSnapshot<T>) => boolean) => boolean' is not assignable to type '(action: (a: DataSnapshot & { key: string; }) => boolean | void) => boolean'.
Types of parameters 'action' and 'action' are incompatible.
Types of parameters 'a' and 'a' are incompatible.
Type 'DatabaseSnapshot<T>' is not assignable to type 'DataSnapshot & { key: string; }'.
Type 'DatabaseSnapshotExists<T>' is not assignable to type 'DataSnapshot & { key: string; }'.
Type 'DatabaseSnapshotExists<T>' is not assignable to type '{ key: string; }'.
Types of property 'key' are incompatible.
Type 'string | null' is not assignable to type 'string'.
Type 'null' is not assignable to type 'string'.
52 export interface DatabaseSnapshotDoesNotExist<T> extends firebase.database.DataSnapshot {
here's my complete app.module.ts file :
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { environment } from '../environments/environment';
import {AngularFireModule} from '#angular/fire/compat';
import { AngularFireDatabaseModule } from '#angular/fire/compat/database';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
#NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
AngularFireModule.initializeApp(environment.firebase),
AngularFireDatabaseModule,
BrowserAnimationsModule,
],
providers: [ ],
bootstrap: [AppComponent]
})
export class AppModule { }
I already tried to delete and reinstall the package but that didn't work.
Also, i have an older project with exactly the same line of code and the same version of angular and angular/fire ("#angular/core": "^14.0.0",
"#angular/fire": "^7.4.1") which work but i can't create a new one.
Any ideas ?
Reason
The reason of this error is change of forEach() signature of firebase.database.DataSnapshot in firebase#9.9.2. Probably in your old project you have an older version (you can check in package-lock.json or in your node_modules) and the error will appear if you run npm update --save there.
These are interfaces from #angular/fire:
export interface DatabaseSnapshotExists<T> extends firebase.database.DataSnapshot {
exists(): true;
val(): T;
forEach(action: (a: DatabaseSnapshot<T>) => boolean): boolean;
}
export interface DatabaseSnapshotDoesNotExist<T> extends firebase.database.DataSnapshot {
exists(): false;
val(): null;
forEach(action: (a: DatabaseSnapshot<T>) => boolean): boolean;
}
In firebase#9.9.2 firebase.database.DataSnapshot has such method:
forEach(
action: (
a: firebase.database.DataSnapshot & { key: string }
) => boolean | void
): boolean;
In firebase#9.9.1 it was:
forEach(
action: (a: firebase.database.DataSnapshot) => boolean | void
): boolean;
Solution
You can install firebase#9.9.1 explicitly to get rid of this error (npm install firebase#9.9.1 --save --save-exact). But remember to update it later when this issue is fixed: https://github.com/angular/angularfire/issues/3255
Update
The problem is solved with firebase#9.9.3. firebase.database.DataSnapshot again has the same forEach signature as in firebase#9.9.1. So just use firebase#9.9.3 (or newer) or remove it from package.json and use version picked up by #angular/fire.
I got the same error message after I updated lots of Node modules using npm update, including updating Firebase 9.9.4 to Firebase 9.10.0. Reverting to Firebase 9.9.1 didn't fix the problem. I reverted my project to the backup and updated the Node modules one by one, checking if Angular started up. The culprit turned out to be TypeScript, updated from 4.7.4 to 4.8.3. Staying with TypeScript 4.7.4 with project runs fine.
angular/fire 7.5.0 firebase 9.16.0
open the interfaces.d.ts the file that generates the error
add at the end of the row <T>
export interface QueryDocumentSnapshot<T> extends firebase.firestore.QueryDocumentSnapshot<T>
I am Facing the same problem, so i back to the version #9.9.1 the issue has been resolved after that, please enter the below code for resolving this issue-
npm install firebase#9.9.1 --save --save-exact
Hope it works.
I changed the interfaces.d.ts with this code, then i can get any collection from firestore.
export interface DocumentSnapshotExists<DocumentData> extends firebase.firestore.DocumentSnapshot {
readonly exists: true;
data(options?: SnapshotOptions): any;
}
export interface DocumentSnapshotDoesNotExist extends firebase.firestore.DocumentSnapshot {
readonly exists: false;
data(options?: SnapshotOptions): undefined;
get(fieldPath: string | FieldPath, options?: SnapshotOptions): undefined;
}
export interface QueryDocumentSnapshot<DocumentData> extends firebase.firestore.QueryDocumentSnapshot {
data(options?: SnapshotOptions): any;
}
Just open following file:
node_modules/#angular/fire/compat/firestore/interfaces.d.ts
You can see below that the subclasses have the wrong return value
Change it to this
Basically you just need to add <T> on the end.
I want to get the ReturnType of useControllerProps rules but I get an ts error:
Type 'Omit<Partial<{ required: string | ValidationRule<boolean>; min: ValidationRule<string | number>; max: ValidationRule<string | number>; ... 12 more ...; deps: string | string[]; }>, "valueAsNumber" | ... 2 more ... | "disabled"> | undefined' does not satisfy the constraint '(...args: any) => any'.
Type 'undefined' is not assignable to type '(...args: any) => any'.ts(2344)
Code:
export interface IReactHookFormInput {
label: string;
name: string;
rules: ReturnType<UseControllerProps['rules']>
}
In an existing code base the ElementUI and Vue2 packages got updated. The users are relying on what looks to be unintended behavior from the outdated DatePicker UI component.
The date is visually formatted as 30/01/2022 in the input field of the DatePicker elements.
To speed up typing users were entering 30012022 into the field instead. This behavior disappeared after the updates. Only entering the date with the / separator gets accepted.
How do I overwrite the vendor methods of the ElementUI Date Time component to ease the input validation?
Replacing validation can be done by wrapping the el-date-picker into your own component. The trick is to use $nextTick inside mounted() and then access the method you want to replace through a reference on the wrapped component.
A small code example of the .vue file using TypeScript:
<template>
<el-date-picker
ref="customDatePicker"
:type="type"
:size="size"
:value="value"
:clearable="clearable"
:format="displayFormat"
:value-format="valueFormat" />
</template>
<script lang="ts">
import moment from 'moment'
import { Component, Prop, Vue } from 'vue-property-decorator'
type PickerType = 'year' | 'month' | 'date' | 'dates' | 'datetime' | ' week' | 'datetimerange' | 'daterange' | 'monthrange'
type Size = 'large' | 'small' | 'mini'
#Component
export default class RexDatePicker extends Vue {
#Prop()
readonly value: any
#Prop({ type: String, default: 'small' })
readonly size!: Size
#Prop({ type: String, default: 'date' })
readonly type!: PickerType
#Prop({ type: String, default: 'yyyy-MM-dd' })
readonly valueFormat!: string
data() {
return {
clearable: this.$attrs.clearable !== 'false'
}
}
get displayFormat() : string {
if (this.type === 'year') {
return 'yyyy'
}
return 'dd/MM/yyyy'
}
mounted() {
this.$nextTick(() => {
var elPicker: any = this.$refs.customDatePicker
if (this.type === 'date' || this.type === 'daterange') {
// inject custom date input behavior
const originalParseFunction = elPicker.parseString
elPicker.parseString = function (value) {
value = expandNumbersToDate(value)
return originalParseFunction(value)
}
}
})
}
}
function expandNumbersToDate(value) {
// expects String, Date or an Array of those two
if (Object.prototype.toString.call(value) === '[object String]') {
var currentMonth = moment().format('MM')
var currentYear = moment().format('YYYY')
value = value.replace(/^[^\d]*(\d{2})[^\d]*$/, `$1/${currentMonth}/${currentYear}`)
value = value.replace(/^[^\d]*(\d{2})(\d{2})[^\d]*$/, `$1/$2/${currentYear}`)
value = value.replace(/^[^\d]*(\d{2})\/?(\d{2})\/?(\d{4})[^\d]*$/, '$1/$2/$3')
}
if (Array.isArray(value)) {
value = value.map(date => expandNumbersToDate(date))
}
return value
}
</script>
I need to remove the value from arrayed query parameter. Suppose, when query is
{
item_ids: [ "12", "13" ],
other_param: [ "alpha", "bravo" ]
}
my function removeElementFromArrayedQueryParameter('item_ids', 13) must turn query to:
{
item_ids: [ "12" ],
other_param: [ "alpha", "bravo" ]
}
Implementation (TypeScript):
function removeElementFromArrayedQueryParameter(key: string, value: string): void {
/** 〔Theory〕 Preventing 'NavigationDuplicated: Navigating to current location ("/〇〇") is not allowed' */
if (isEmptyObject(RoutingHelper.router.currentRoute.query)) {
return;
}
if (!Array.isArray(RoutingHelper.router.currentRoute.query[key])) {
return;
}
const updatedQuery: QueryParameters = {
...RoutingHelper.router.currentRoute.query as object
};
removeSingleElementFromArrayByPredicateMutably(
updatedQuery[key] as Array<string>, (arrayElement: string): boolean => arrayElement === value
);
console.log(JSON.stringify(updatedQuery, null, 2)); // I checked: the element has been romoved
// it's the router instance created by new VueRouter({})
RoutingHelper.router.push({
query: updatedQuery
})
.catch((error: Error): void => {
console.error(error)
});
}
function isEmptyObject(potentialObject: unknown): potentialObject is object {
if (typeof potentialObject !== "object" || potentialObject === null) {
return false;
}
return Object.entries(potentialObject as {[key: string]: unknown}).length === 0;
}
Although the removing of target element from updatedQuery successful (checked by manual testing), I have console error:
{
"_name": "NavigationDuplicated",
"name": "NavigationDuplicated",
"message": "Navigating to current location (\"/page?item_ids=12\") is not allowed"
}
"message" in console error contains right target location, but actually one of item_ids has not been removed from URI.
The console error is right about route name is same, but I don't going to redirect on same page: I just want to remove one query parameter. router.push casts similar error.
Update
Please note that TypeScript does not allow to write as
this.$router.replace({
...this.$router.currentRoute,
query
});
TS2769: No overload matches this call.
Overload 1 of 2, '(location: RawLocation): Promise<Route>', gave the following error.
Argument of type '{ query: Dictionary<string | (string | null)[] | null | undefined>; path: string; name?: string |
null | undefined; hash: string; params: Dictionary<string>; fullPath: string; matched: RouteRecord[]; redirectedFrom?: s
tring | undefined; meta?: any; }' is not assignable to parameter of type 'RawLocation'.
Type '{ query: Dictionary<string | (string | null)[] | null | undefined>; path: string; name?: string | null | und
efined; hash: string; params: Dictionary<string>; fullPath: string; matched: RouteRecord[]; redirectedFrom?: string | un
defined; meta?: any; }' is not assignable to type 'Location'.
Types of property 'name' are incompatible.
Type 'string | null | undefined' is not assignable to type 'string | undefined'.
Type 'null' is not assignable to type 'string | undefined'.
Overload 2 of 2, '(location: RawLocation, onComplete?: Function | undefined, onAbort?: ErrorHandler | undefined): void
', gave the following error.
Argument of type '{ query: Dictionary<string | (string | null)[] | null | undefined>; path: string; name?: string |
null | undefined; hash: string; params: Dictionary<string>; fullPath: string; matched: RouteRecord[]; redirectedFrom?: s
tring | undefined; meta?: any; }' is not assignable to parameter of type 'RawLocation'.
Type '{ query: Dictionary<string | (string | null)[] | null | undefined>; path: string; name?: string | null | und
efined; hash: string; params: Dictionary<string>; fullPath: string; matched: RouteRecord[]; redirectedFrom?: string | un
defined; meta?: any; }' is not assignable to type 'Location'.
Types of property 'name' are incompatible.
Type 'string | null | undefined' is not assignable to type 'string | undefined'.
Type 'null' is not assignable to type 'string | undefined'.
If the are no mistake in TypeScript types, above solution is not safe.
this.$router.replace({
...this.$router.name === null ? {} : RoutingHelper.router.currentRoute,
query: updatedQuery
})
does not fix it.
You should update your new route like this
function removeFromQuery(route, queryName, queryValue)
{
const query = Object.assign({}, route.query);
if (queryName in query)
{
const idx = query[queryName].indexOf(queryValue);
if (idx !== -1)
{
query[queryName].splice(idx, 1);
this.$router.replace({
...this.$router.currentRoute,
query
});
}
}
}
The updatedQuery query is not the deep clone of RoutingHelper.router.currentRoute.query. Below code is not enough to create the deep copy of query:
const updatedQuery: QueryParameters = {
...RoutingHelper.router.currentRoute.query as object
};
So, when execute
RoutingHelper.router.push({
query: updatedQuery
})
we don't subtitute query to new value. That why error occurs.
Use lodash or other libraries provides deep cloning, or use own implementation of deep cloning.
So I have this code, it decides what to do on a transition between two pages and it works well :
export default {
transition: {
mode: 'out-in',
css: false,
beforeEnter (el) {
console.log('set transition');
},
enter (el, done) {
console.log('enter transition');
done();
},
leave (el, done) {
console.log('leave transition');
done();
},
}
}
Now I would like to specify what to do depending on what the next page is. So I've to use the transition(to, from) method according to the documentation. But unfortunately I can't mix this function with parameters like mode: 'out-in' and I can't manage to call the leave(el, done) function with the to, from parameters.
Does anyone knows how to combine this ? Thanks.
Maybe you found the solution, but I managed to combine transition with routes (to, from) and the object transition.
Let me explain :
If you look a the TypeScript declaration for vue, especially the ComponentOptions interface (node_modules/#nuxt/types/app/vue.d.ts)
Here's what we have :
declare module 'vue/types/options' {
// eslint-disable-next-line no-unused-vars,#typescript-eslint/no-unused-vars
interface ComponentOptions<V extends Vue> {
// eslint-disable-next-line #typescript-eslint/ban-types
asyncData?(ctx: Context): Promise<object | void> | object | void
fetch?(ctx: Context): Promise<void> | void
fetchKey?: string | ((getKey: (id: string) => number) => string)
fetchDelay?: number
fetchOnServer?: boolean | (() => boolean)
head?: MetaInfo | (() => MetaInfo)
key?: string | ((to: Route) => string)
layout?: string | ((ctx: Context) => string)
loading?: boolean
middleware?: Middleware | Middleware[]
scrollToTop?: boolean
transition?: string | Transition | ((to: Route, from: Route | undefined) => string | Transition)
validate?(ctx: Context): Promise<boolean> | boolean
watchQuery?: boolean | string[] | ((newQuery: Route['query'], oldQuery: Route['query']) => boolean)
meta?: { [key: string]: any }
}
}
The transition attribute is defined as follow :
transition?: string | Transition | ((to: Route, from: Route | undefined) => string | Transition)
So, by using the function approach, you must give either a string or a Transition object.
Example :
transition(to, from) {
if(!from) {
// returns a string
return 'my-custom-css-animation';
}
// returns an object Transition
return {
name: 'custom',
appear:false,
css: false,
beforeLeave() {
// before leave hook
},
leave(el, done) {
// leave hook
},
beforeEnter(el) {
// before enter hook
},
enter(el, done) {
// Enter hook
}
}
}
You should use pageTransition instead.
And did you try with a function?
export default {
pageTransition (to, from) {
if (!from) { return 'slide-left' }
return +to.query.page < +from.query.page ? 'slide-right' : 'slide-left'
}
}
Doc here: https://fr.nuxtjs.org/api/pages-transition/#fonction