I'm building a Chrome app. The app is written with TypeScript (Angular2).
I would like to push notifications. Here's the code :
import {Injectable} from 'angular2/core';
#Injectable()
export class NotificationService {
constructor() {
if(Notification.permission !== 'granted') {
Notification.requestPermission();
}
}
}
When gulp build the app, it says :
src/scripts/stream/notification.service.ts(6) Cannot find name 'Notification'.
I tried to wrap my class inside :
/* tslint:disable */
... the code
/* tslint:enable */
But it does not change anything.
Is there a way with tslint.json file to tell Typescript that this is a global variable ?
With jshint it would be something like that :
"globals": {
"Notification": false
}
A couple of options here:
Add the following line to the top of your file.
declare var Notification: any;
This will make the transpiler pass but won't give you the much of TypeScript's features.
Download the definition type (chrome.d.ts).
TSD seems to be the most popular definition manager.
Typings is another promising alternative.
A generic typing file is available via this GitHub TypeScript issue;
Create a new typing definition file called notification.d.ts and add the following code.
type NotificationPermission = "default" | "denied" | "granted";
type NotificationDirection = "auto" | "ltr" | "rtl";
interface NotificationPermissionCallback {
(permission: NotificationPermission): void;
}
interface NotificationOptions {
dir?: NotificationDirection;
lang?: string;
body?: string;
tag?: string;
image?: string;
icon?: string;
badge?: string;
sound?: string;
vibrate?: number | number[],
timestamp?: number,
renotify?: boolean;
silent?: boolean;
requireInteraction?: boolean;
data?: any;
actions?: NotificationAction[]
}
interface NotificationAction {
action: string;
title: string;
icon?: string;
}
declare class Notification extends EventTarget {
constructor(title: string, options?: NotificationOptions);
static readonly permission: NotificationPermission;
static requestPermission(): Promise<NotificationPermission>;
static requestPermission(deprecatedCallback: (permission: NotificationPermission) => void): void;
static readonly maxActions: number;
onclick: EventListenerOrEventListenerObject;
onerror: EventListenerOrEventListenerObject;
close(): void;
readonly title: string;
readonly dir: NotificationDirection;
readonly lang: string;
readonly body: string;
readonly tag: string;
readonly image: string;
readonly icon: string;
readonly badge: string;
readonly sound: string;
readonly vibrate: number[];
readonly timestamp: number;
readonly renotify: boolean;
readonly silent: boolean;
readonly requireInteraction: boolean;
readonly data: any;
readonly actions: NotificationAction[]
}
Making sure the typings file is included in your project (tsconfig.json);
"typeRoots": [
"typings/notification.d.ts"
]
You should now be able to access Notification.
It looks like you are missing the typing definitions for Chrome.
You can install them using the tsd tool.
First you need to install tsd.
$ npm install tsd -g
Then you can use it to install the type definitions for Chrome in your project.
$ tsd install chrome
You can find more info on tsd here.
Note: make sure you have only 1 tsd file defined for a library.
I haven't found the d.ts files for the Notifications API, but i have found a little trick.
if("Notification" in window){
let _Notification = window["Notification"];
}
_Notification will have the same properties as Notification, and can be used the same. This will get around any errors in TypeScript.
Related
Why we cant use an decorator within a NestJS service? Here is a example on how I tried to do, but it does not work.
Decorator: #User()
// user.decorator.ts
import { createParamDecorator } from '#nestjs/common';
export const User = createParamDecorator((data, req): {userId, email} => {
return data ? req.user[data] : req.user;
});
When I call this decorator into a service, I got this message: Unable to resolve signature of property decorator when called as an expression
// connect.service.ts
import { Injectable, Inject } from '#nestjs/common';
import { User } from '../account/user/user.decorator';
#Injectable()
export class ConnectService {
#User()
userInfo;
}
It looks like you are trying to add a decorator on an Injectable() I don't think you can do that. It would need to be on a method so that when it is called some magic can happen behind the scenes. Consider using class-validator and the validationPipe
For example:
#Get('vitalsByEncounterID')
async getVitalsByEncounterID(#Query() params: VitalsByEncounterPathDTO, #Headers(DFDHeaders.xRequestId) requestId: string): Promise<VitalSignsDTO[]> {}
Then you'd decorate the class
export class VitalsByEncounterPathDTO {
#IsString()
#IsNotEmpty()
#ApiModelProperty({ required: true, description: 'iCentra id for the patient' })
patientId: string;
#IsString()
#IsNotEmpty()
#ApiModelProperty({ required: true, description: 'an encounter id for the patient' })
encounterId: string;
}
You're trying to decorate a property with a ParamDecorator, that's why you get this error message.
Can you give some more details on your usecase? That would maybe help someone to give some insights on what you're trying to achieve.
How can i access (read) the state of a reducer state within a another reducer in NGRX?
It is a very similar question to this.
Does NGRX offers any other solution to this?
I just stumbled upon this question when thinking about doing something similar. I needed a copy of some state information from a different reducer as a temporary "editing" data set that could be canceled and reverted back to the "recorded" data set.
I ended up extending my UI reducer (the reducer that held the state/edits for the current user's session) to include a property to hold a copy of data from my Data reducer (the reducer that represents what is stored in the database). That data gets passed in via a "Start" action.
Here is an abbreviated copy of my UI action:
import { Action } from "#ngrx/store";
import {
ICableFeature
} from "../../shared/models";
export enum UIActionTypes {
...
UI_EDIT_CUSTOM_TAGS_START = "[UI] Edit Custom Tags Start",
UI_EDIT_CUSTOM_TAGS_UPDATE = "[UI] Edit Custom Tags Update",
UI_EDIT_CUSTOM_TAGS_SAVE = "[UI] Edit Custom Tags Save",
UI_EDIT_CUSTOM_TAGS_SUCCESSFUL = "[UI] Edit Custom Tags Successful",
UI_EDIT_CUSTOM_TAGS_FAILED = "[UI] Edit Custom Tags Failed",
UI_EDIT_CUSTOM_TAGS_CANCELED = "[UI] Edit Custom Tags Canceled"
}
...
export class EditCustomTagsStart implements Action {
readonly type = UIActionTypes.UI_EDIT_CUSTOM_TAGS_START;
constructor(public payload: ICableFeature) {}
}
export class EditCustomTagsUpdate implements Action {
readonly type = UIActionTypes.UI_EDIT_CUSTOM_TAGS_UPDATE;
constructor(public payload: ICableFeature) {} // This payload has a copy of the data I needed from the other reducer. Make sure it is a copy and not the same object!
}
export class EditCustomTagsSave implements Action {
readonly type = UIActionTypes.UI_EDIT_CUSTOM_TAGS_SAVE;
constructor() {}
}
export class EditCustomTagsSuccessful implements Action {
readonly type = UIActionTypes.UI_EDIT_CUSTOM_TAGS_SUCCESSFUL;
constructor() {}
}
export class EditCustomTagsFailed implements Action {
readonly type = UIActionTypes.UI_EDIT_CUSTOM_TAGS_FAILED;
constructor(public payload: string) {}
}
export class EditCustomTagsCanceled implements Action {
readonly type = UIActionTypes.UI_EDIT_CUSTOM_TAGS_CANCELED;
constructor() {}
}
export type UIActions =
...
| EditCustomTagsStart
| EditCustomTagsUpdate
| EditCustomTagsSuccessful
| EditCustomTagsFailed
| EditCustomTagsCanceled;
And here is an abbreviated copy of my UI reducer:
import * as fromUI from "../actions/ui.actions";
import {
IOrchestratorState,
IOrchestratorStatusState,
ICableFeature
} from "../../shared/models";
export const uiFeatureKey = "ui";
export interface State {
showScroll: boolean;
fillingGaps: boolean;
fillGapStatus: IOrchestratorStatusState;
currentFillGapState: IOrchestratorState;
editingCustomTags: boolean;
customTagEdits: ICableFeature;
}
export const initialState: State = {
showScroll: true,
fillingGaps: false,
fillGapStatus: null,
currentFillGapState: null,
editingCustomTags: false,
customTagEdits: null
};
export function reducer(state = initialState, action: fromUI.UIActions) {
switch (action.type) {
...
case fromUI.UIActionTypes.UI_EDIT_CUSTOM_TAGS_START:
return {
...state,
editingCustomTags: true,
customTagEdits: action.payload // This is a copy of the data I needed from the other reducer
};
case fromUI.UIActionTypes.UI_EDIT_CUSTOM_TAGS_UPDATE:
return {
...state,
customTagEdits: action.payload // This is the updated information from user edits, not saved.
// I can also create a router guard that checks to makes sure the data in this
// property and the data in my Data store are the same before the page is deactivated
};
case fromUI.UIActionTypes.UI_EDIT_CUSTOM_TAGS_SUCCESSFUL:
case fromUI.UIActionTypes.UI_EDIT_CUSTOM_TAGS_FAILED:
case fromUI.UIActionTypes.UI_EDIT_CUSTOM_TAGS_CANCELED:
return {
...state,
editingCustomTags: false,
customTagEdits: null
};
default:
return state;
}
}
As you can see, by passing the data from one reducer to the other as payloads in actions, I am able to maintain pure functions in my reducers.
I hope this helps!
I would like to add my own custom behavior (server-side) to the closing tab(s) operation, so I think I should extend this method closeFile() of the
DocumentManager https://github.com/jupyterlab/jupyterlab/blob/master/packages/docmanager/src/manager.ts#L177.
I have a custom file browser plugin (extension) that works well if I use it with JupyterLab's core IDocumentManager but not if I use it with the extended/overwritten IMyDocumentManager like here:
const browserPlugin: JupyterLabPlugin<void> = {
id: "my:fs",
requires: [IMyDocumentManager, ISettingRegistry, IMainMenu],
activate: activateMyBrowser,
autoStart: true
};
My IMyDocumentManager looks like this:
import { IDocumentManager, DocumentManager } from '#jupyterlab/docmanager';
import { Token } from '#phosphor/coreutils';
export interface IMyDocumentManager extends IDocumentManager {}
export const IMyDocumentManager = new Token<IMyDocumentManager ('#jupyterlab/docmanager:IDocumentManager');
export class MyDocumentManager extends DocumentManager implements IMyDocumentManager {
closeFile(path: string): Promise<void> {
console.log("Test override a method for closing: " + path);
return super.closeFile(path);
}
}
When I load JupyterLab in the browser I get the error:
It's probably because I have to define the Token differently. Instead of new Token<IMyDocumentManager ('#jupyterlab/docmanager:IDocumentManager') I should use some other string than '#jupyterlab/docmanager:IDocumentManager' but I don't really know what. It's hard to infer from the PhosphorJS code.
I am trying to correctly type a react component with flow and apollo graphql. I keep getting a flow error message. I am using react-apollo 2.0.1 and flow 0.53.1
// #flow
/**
*
* CompanyName
*
*/
import React from 'react';
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';
import type { OperationComponent, ChildProps } from 'react-apollo';
type Company = {
id: string,
name: string,
};
type Response = {
company: Company,
};
type Props = {
className: ?string,
};
class CompanyName extends React.Component<ChildProps<Props, Response>> {
render() {
return (
<span className={this.props.className}>
{!!this.props.data.company && this.props.data.company.name}
</span>
);
}
}
const query = gql`
query {
company {
id
name
}
}
`;
const withCompanyName: OperationComponent<Response, Props> = graphql(query);
export default withCompanyName(CompanyName); // this line gives a flow error
I get an error on the last line of code saying that the type is incompatible. Everything else validates correctly.
The error message is: CompanyName (class type: CompanyName) This type is incompatible with StatelessComponent (union: type application of polymorphic type: type StatelessComponent | class type: type application of identifier React$Component)
I am able to get it to work properly if I change it to a stateless functional component, but I need to get this working for class components.
Update:
Here is my .flowconfig
[ignore]
[include]
[libs]
[options]
module.name_mapper='.*\(.gql\)' -> 'empty/object'
I am using the empty package to prevent gql imports from causing a flow error.
I'm using the packages meteortypescript:compiler and meteortypescript:typescript-libs. I'm trying to query a collection for a record like this:
MyCollection.findOne({email: 'user#example.com', username: 'bob'});
And I'm getting this error:
error TS2345: Argument of type '{ email: string; username: string; }'
is not assignable to parameter of type 'Selector'.
This makes no sense, because I can see that the type Selector in the .d.ts file I'm using for Meteor is defined as interface Selector extends Object {}, which should not be giving a problem. Any pointers?
Combine interface Selector extends Object {} with Argument of type '{ email: string; username: string; }' is not assignable to parameter of type 'Selector'. leads me to think you have a freshness aka strict object checking problem. Here is a simplified example:
interface Selector extends Object {}
function foo(arg:Selector){}
foo({ email: 'asfd#asdf.com', username: 'asdf' }); // same error you are getting